pax_global_header00006660000000000000000000000064147213741160014520gustar00rootroot0000000000000052 comment=9a0dacceecf90cf4a3e2fc5ecfbd4abc31396db1 golang-github-protonmail-gopenpgp-v3-3.1.0/000077500000000000000000000000001472137411600205755ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-v3-3.1.0/.github/000077500000000000000000000000001472137411600221355ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-v3-3.1.0/.github/actions/000077500000000000000000000000001472137411600235755ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-v3-3.1.0/.github/actions/build-gosop/000077500000000000000000000000001472137411600260215ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-v3-3.1.0/.github/actions/build-gosop/action.yml000066400000000000000000000031131472137411600300170ustar00rootroot00000000000000name: 'build-gosop' description: 'Build gosop from the current branch' inputs: gopenpgp-ref: description: 'gopenpgp branch tag or commit to build from' required: true default: '' binary-location: description: 'Path for the gosop binary' required: true default: './gosop-${{ github.sha }}' runs: using: "composite" steps: - name: Checkout gopenpgp uses: actions/checkout@v4 with: ref: ${{ inputs.gopenpgp-ref }} path: gopenpgp - name: Set env run: echo "GOSOP_BRANCH_REF=$(./.github/test-suite/determine_gosop_branch.sh)" >> $GITHUB_ENV shell: bash - name: Print gosop branch run: echo ${{ env.GOSOP_BRANCH_REF}} shell: bash # Build gosop - name: Set up latest golang uses: actions/setup-go@v3 with: go-version: ^1.18 - name: Check out gosop uses: actions/checkout@v4 with: repository: ProtonMail/gosop ref: ${{ env.GOSOP_BRANCH_REF}} path: gosop - name: Cache go modules uses: actions/cache@v3 with: path: | ~/.cache/go-build ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go- - name: Build gosop run: ./.github/test-suite/build_gosop.sh shell: bash # Test the binary - name: Print gosop version run: ./gosop/gosop version --extended shell: bash # Move and rename binary - name: Move binary run: mv gosop/gosop ${{ inputs.binary-location }} shell: bash golang-github-protonmail-gopenpgp-v3-3.1.0/.github/test-suite/000077500000000000000000000000001472137411600242435ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-v3-3.1.0/.github/test-suite/build_gosop.sh000077500000000000000000000004331472137411600271100ustar00rootroot00000000000000VERSION=$(awk '/^module github.com\/ProtonMail\/gopenpgp\/v[0-9]+/ {print $NF}' gopenpgp/go.mod | awk -F'v' '{print $2}') cd gosop echo "replace github.com/ProtonMail/gopenpgp/v${VERSION} => ../gopenpgp" >> go.mod go get github.com/ProtonMail/gopenpgp/v${VERSION}/crypto go build . golang-github-protonmail-gopenpgp-v3-3.1.0/.github/test-suite/config.json.template000066400000000000000000000006621472137411600302210ustar00rootroot00000000000000{ "drivers": [ { "id": "gosop-branch", "path": "__GOSOP_BRANCH__" }, { "id": "gosop-target", "path": "__GOSOP_TARGET__" }, { "path": "__SQOP__" }, { "path": "__GPGME_SOP__" }, { "path": "__SOP_OPENPGPJS__" }, { "path": "__RNP_SOP__" } ], "rlimits": { "DATA": 1073741824 } } golang-github-protonmail-gopenpgp-v3-3.1.0/.github/test-suite/determine_gosop_branch.sh000077500000000000000000000003271472137411600313040ustar00rootroot00000000000000VERSION=$(awk '/^module github.com\/ProtonMail\/gopenpgp\/v[0-9]+/ {print $NF}' gopenpgp/go.mod | awk -F'v' '{print $2}') if [ "$VERSION" -eq 3 ]; then echo "gosop-gopenpgp-v3" else echo "gosop-gopenpgp-v2" fi golang-github-protonmail-gopenpgp-v3-3.1.0/.github/test-suite/prepare_config.sh000077500000000000000000000006061472137411600275670ustar00rootroot00000000000000CONFIG_TEMPLATE=$1 CONFIG_OUTPUT=$2 GOSOP_BRANCH=$3 GOSOP_TARGET=$4 cat $CONFIG_TEMPLATE \ | sed "s@__GOSOP_BRANCH__@${GOSOP_BRANCH}@g" \ | sed "s@__GOSOP_TARGET__@${GOSOP_TARGET}@g" \ | sed "s@__SQOP__@${SQOP}@g" \ | sed "s@__GPGME_SOP__@${GPGME_SOP}@g" \ | sed "s@__SOP_OPENPGPJS__@${SOP_OPENPGPJS_V2}@g" \ | sed "s@__RNP_SOP__@${RNP_SOP}@g" \ > $CONFIG_OUTPUTgolang-github-protonmail-gopenpgp-v3-3.1.0/.github/workflows/000077500000000000000000000000001472137411600241725ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-v3-3.1.0/.github/workflows/android.yml000066400000000000000000000016501472137411600263370ustar00rootroot00000000000000name: Gomobile for Android on: push: branches: [ main ] pull_request: branches: [ main, v3 ] jobs: build: name: Build library for Android with gomobile runs-on: ubuntu-20.04 steps: - name: Set up JDK 1.8 uses: actions/setup-java@v1 with: java-version: 1.8 - name: Set up Go 1.x uses: actions/setup-go@v2 with: go-version: ^1.16 id: go - name: Install NDK uses: nttld/setup-ndk@v1 with: ndk-version: r23c link-to-sdk: true - name: Checkout uses: actions/checkout@v4 - name: Build run: | for d in $ANDROID_NDK_HOME/../23*; do ANDROID_NDK_HOME=$d done ./build.sh android find dist - name: Upload Android artifacts uses: actions/upload-artifact@v4 with: name: Android build path: dist/android if-no-files-found: error golang-github-protonmail-gopenpgp-v3-3.1.0/.github/workflows/go.yml000066400000000000000000000017441472137411600253300ustar00rootroot00000000000000name: Go test and lint on: push: branches: [ main ] pull_request: branches: [ main, v3 ] jobs: test: name: Test with latest golang runs-on: ubuntu-latest steps: - name: Check out repo uses: actions/checkout@v4 - name: Set up latest golang uses: actions/setup-go@v3 with: go-version: ^1.18 - name: Test run: go test -v -race ./... test-old: name: Test with 1.17 runs-on: ubuntu-latest steps: - name: Check out repo uses: actions/checkout@v4 - name: Set up Go 1.17 uses: actions/setup-go@v3 with: go-version: 1.17 - name: Test run: go test -v -race ./... lint: name: Lint runs-on: ubuntu-latest steps: - uses: actions/setup-go@v3 with: go-version: 1.17 - uses: actions/checkout@v4 - name: golangci-lint uses: golangci/golangci-lint-action@v3 with: version: v1.54.2golang-github-protonmail-gopenpgp-v3-3.1.0/.github/workflows/ios.yml000066400000000000000000000015451472137411600255140ustar00rootroot00000000000000name: Gomobile for iOS on: push: branches: [ main ] pull_request: branches: [ main, v3 ] jobs: build: name: Build library for iOS with gomobile runs-on: macos-latest steps: - name: Set up xcode 15.3.0 uses: maxim-lobanov/setup-xcode@v1 with: xcode-version: 15.3.0 id: xcode - name: Set up Go 1.x uses: actions/setup-go@v2 with: go-version: ^1.16 id: go - name: Checkout uses: actions/checkout@v4 - name: Build env: platform: ${{ 'iOS Simulator' }} run: | ./build.sh apple find dist - name: Upload xcframework uses: actions/upload-artifact@v4 with: name: gopenpgp.xcframework path: dist/apple/gopenpgp.xcframework if-no-files-found: error golang-github-protonmail-gopenpgp-v3-3.1.0/.github/workflows/sop-test-suite.yml000066400000000000000000000102161472137411600276220ustar00rootroot00000000000000name: SOP interoperability test suite on: pull_request: branches: [ main, v3 ] jobs: build-gosop: name: Build gosop from branch runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Build gosop from branch uses: ./.github/actions/build-gosop with: binary-location: ./gosop-${{ github.sha }} # Upload as artifact - name: Upload gosop artifact uses: actions/upload-artifact@v4 with: name: gosop-${{ github.sha }} path: ./gosop-${{ github.sha }} build-gosop-target: name: Build gosop from target runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Build gosop from branch uses: ./.github/actions/build-gosop with: gopenpgp-ref: ${{ github.base_ref }} binary-location: ./gosop-target # Upload as artifact - name: Upload gosop-target artifact uses: actions/upload-artifact@v4 with: name: gosop-target path: ./gosop-target 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 }} needs: - build-gosop - build-gosop-target steps: - name: Checkout uses: actions/checkout@v4 # Fetch gosop from target - name: Download gosop-target uses: actions/download-artifact@v4 with: name: gosop-target # Test gosop-target - name: Make gosop-target executable run: chmod +x gosop-target - name: Print gosop-target version run: ./gosop-target version --extended # Fetch gosop from branch - name: Download gosop-branch uses: actions/download-artifact@v4 with: name: gosop-${{ github.sha }} - name: Rename gosop-branch run: mv gosop-${{ github.sha }} gosop-branch # Test gosop-branch - name: Make gosop-branch executable run: chmod +x gosop-branch - name: Print gosop-branch version run: ./gosop-branch version --extended # Run test suite - name: Prepare test configuration run: ./.github/test-suite/prepare_config.sh $CONFIG_TEMPLATE $CONFIG_OUTPUT $GITHUB_WORKSPACE/gosop-branch $GITHUB_WORKSPACE/gosop-target 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-target: name: Compare with target 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.0.0 with: results: ${{ steps.download-test-results.outputs.download-path }}/test-suite-results.json output: baseline-comparison.json baseline: gosop-target target: gosop-branch golang-github-protonmail-gopenpgp-v3-3.1.0/.gitignore000066400000000000000000000000771472137411600225710ustar00rootroot00000000000000.DS_Store bin dist vendor .vscode *.out *.html reports .idea v3golang-github-protonmail-gopenpgp-v3-3.1.0/.golangci.yml000066400000000000000000000062611472137411600231660ustar00rootroot00000000000000linters-settings: godox: keywords: # default keywords are TODO, BUG, and FIXME, but we override this by ignoring TODO - BUG - FIXME funlen: lines: 150 statements: 80 cyclop: # the minimal code complexity to report max-complexity: 26 gocognit: min-complexity: 45 issues: exclude-use-default: false exclude: - Using the variable on range scope `tt` in function literal - GetJsonSHA256Fingerprints should be GetJSONSHA256Fingerprints - ST1003 # CamelCase variables; see constants/cipher.go - missing output for example, go test can't validate it - variable 'hasExpiredEntity' is only used in the if-statement exclude-rules: - path: crypto/key_clear.go text: "SA1019" - path: crypto/crypto_example_test.go text: "G101: Potential hardcoded credentials" - path: crypto/encrypt_decrypt_test.go text: "Using the variable on range scope" - path: crypto/encrypt_decrypt_err_test.go text: "Using the variable on range scope" - path: crypto/sign_verify_test.go text: "Using the variable on range scope" linters: enable-all: true disable: - dupl # Tool for code clone detection [fast: true, auto-fix: false] - gochecknoglobals # Checks that no globals are present in Go code [fast: true, auto-fix: false] - gochecknoinits # Checks that no init functions are present in Go code [fast: true, auto-fix: false] - golint # Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes [fast: true, auto-fix: false] - goerr113 # Golang linter to check the errors handling expressions [fast: true, auto-fix: false] - gomnd # An analyzer to detect magic numbers. [fast: true, auto-fix: false] - lll # Reports long lines [fast: true, auto-fix: false] - testpackage # Makes you use a separate _test package [fast: true, auto-fix: false] - wsl # Whitespace Linter - Forces you to use empty lines! [fast: true, auto-fix: false] - gofumpt # Enforce a stricter format than gofmt - gci # Enforce blank lines check - nlreturn # Enforce blank lines for return statements - exhaustivestruct # Enforce structures to be fully filled on instantiation - terrible with openpgp configs - paralleltest # Detects missing usage of t.Parallel() method in your Go test - forbidigo # Static analysis tool to forbid use of particular identifiers - thelper # Enforce test helper formatting - revive # Force CamelCase instead of all caps - nilerr # Force return err when not nil - wrapcheck # Force wrapping of external error TODO: when the bug is fixed update the linter - gomoddirectives # Prohibits the use of replace statements - varnamelen # Forbids short var names - ireturn # Prevents returning interfaces - forcetypeassert # Forces to assert types in tests - nonamedreturns # Disallows named returns - exhaustruct # Forces all structs to be named - nosnakecase # Disallows snake case - depguard - nestifgolang-github-protonmail-gopenpgp-v3-3.1.0/CHANGELOG.md000066400000000000000000001337521472137411600224210ustar00rootroot00000000000000# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [3.1.0] 2024-11-25 ### Added - Add decryption option to allow disabling the integrity tag requirement. - Add option to decrypt with signature keys for legacy messages. ### Changed - Rename `profile.Custom.AllowWeakRSA` to `profile.Custom.InsecureAllowWeakRSA` - Update go-crypto to `1.1.3`. ## [3.0.0] 2024-10-07 ### Changed - Remove `Name` field from profile. - Remove signature rejection logic based on hash (handled by go-crypto). - Update go-crypto to `1.1.0`. ## [3.0.0-beta.0] 2024-10-01 ### Added - Add `GetSHA256Fingerprint` method to `Key`. ### Changed - Update go-crypto to `1.1.0-beta.0`. ## [3.0.0-alpha.4] 2024-07-18 ### Changed - Update go-crypto to `1.1.0-alpha.4`. - Remove logic to get a profile by name. - Reduce preset profiles to `Default`, `RFC4880`, and `RFC9580`. - Update go-crypto to check signature details of binding signatures. ## [3.0.0-alpha.3] 2024-06-25 ### Added - API to armor data with the option to remove the checksum ### Changed - All armor functions append a checksum per default for compatibility with certain libraries although the crypto-refresh advises not to. - `Encryption` and `Sign` handle now append a checksum when armoring. If the produced OpenPGP packets are crypto-refresh packets, the checksum is not appended as mandated by the crypto-refresh. ## [3.0.0-alpha.2] 2024-04-12 ### Added - API to serialize KeyRings to binary data: ```go func (keyRing *KeyRing) Serialize() ([]byte, error) ``` - API to parse KeyRings from binary data: ```go func NewKeyRingFromBinary(binKeys []byte) (*KeyRing, error) ``` - API to a create/verify plaintext detached signatures on the encryption/decryption handle instead of just encrypted detached signatures. ## [3.0.0-alpha.1] 2024-03-20 ### Added - Allow to override algorithm in key generation - Always create a verification result on signature verification ### Changed - Update ProtonMail/go-crypto to 1.1.0-alpha.2 ## [3.0.0-alpha.0] 2024-01-18 ### Added - New simplified API that is not backward compatible. - Full support for RFC 9580. - Improved interoperability with other OpenPGP libraries. - Streaming support for all operations. - Introduces profiles for OpenPGP customization. - More documentation and examples. ### Changed - Mobile specific code is moved to the `mobile` package. - Mime specific code is moved to the `mime` package. - Replaces the go-crypto v1 API with the v2 API. ### Removed - The `helper` package, use the crypto package with the new API instead. - `subtle` and `models` package. - Time management code for retrieving and setting timestamps. ## [2.7.5] 2023-31-01 ### Added - API to get signature key IDs for mobile: ```go func (msg *PGPMessage) GetHexSignatureKeyIDsJson() []byte ``` - API to get encryption key IDs for mobile: ```go func (msg *PGPMessage) GetHexEncryptionKeyIDsJson() []byte ``` - API to get the number of key packets in a PGP message: ```go func (msg *PGPSplitMessage) GetNumberOfKeyPackets() (int, error) ``` - API in package `helper` to encrypt a PGP message to an additional key: ```go func EncryptPGPMessageToAdditionalKey(messageToModify *crypto.PGPSplitMessage, keyRing *crypto.KeyRing, additionalKey *crypto.KeyRing) error ``` ## [2.7.4] 2023-10-27 ### Fixed - Ensure that `(SessionKey).Decrypt` functions return an error if no integrity protection is present in the encrypted input. To protect SEIPDv1 encrypted messages, SED packets must not be allowed in decryption. ## [2.7.3] 2023-08-28 ### Added - Add `helper.QuickCheckDecrypt` function to the helper package. The function allows to check with high probability if a session key can decrypt a SEIPDv1 data packet given its 24-byte prefix. ## [2.7.2] 2023-07-17 ### Changed - Updated underlying crypto library ### Fixed - Ensure DecryptSessionKey returns an error for a missing key packet ## [2.7.1] 2023-04-21 ### Added - Add mobile helpers for signature verification with contexts. ## [2.7.0] 2023-04-14 ### Changed - The `SignatureVerificationError` struct now has a `Cause error` field, which is returned by the the Unwrap function. The cause is also included in the error message. NB: If the caller was relying on the exact message of the error, it might break the flow. - When a signature fails verification because of the signature context, it returns a `SignatureVerificationError` with status `constants.SIGNATURE_BAD_CONTEXT` instead of `constants.SIGNATURE_FAILED`. ## Added - Add api for signature context on streams `SignDetachedStreamWithContext`. - Add API for signature context on embedded signatures. ## Fixed - When verifying detached signatures, gopenpgp sometimes needs to reattempt verification a second time to check for edge cases of signature expiration. This logic was broken because it was not rewinding the data readers. ## [2.6.1] 2023-03-22 ### Security fix - Update `github.com/ProtonMail/go-crypto` and `github.com/ProtonMail/go-mime` to fix panic on invalid inputs. ## [2.6.0] 2023-03-15 ### Added - API for adding context to detached signatures: ```go sig, err := keyRing.SignDetachedWithContext(message, context) ``` - API to verify the context of detached signatures: ```go err := keyRing.VerifyDetachedWithContext(message, signature, verifyTime, verificationContext) ``` ### Changed - Update `github.com/ProtonMail/go-crypto` to the latest version - More strictly verify detached signatures: reject detached signatures from revoked and expired keys. - In `GetVerifiedSignatureTimestamp`, use the new `VerifyDetachedSignatureAndHash` function to get the verified signature, instead of parsing the signature packets manually to get the timestamp. - Upgraded golang.org/x/crypto dependency to v0.7.0 ## [2.5.2] 2023-01-25 ### Changed - Update `github.com/ProtonMail/go-crypto` to the latest version ## [2.5.1] 2023-01-24 ### Added - Streaming API to encrypt with compression: - `func (keyRing *KeyRing) EncryptStreamWithCompression` - `func (keyRing *KeyRing) EncryptSplitStreamWithCompression` - `func (sk *SessionKey) EncryptStreamWithCompression` ## [2.5.0] 2022-12-16 ### Changed - Update `github.com/ProtonMail/go-crypto` to the latest version - Update `github.com/ProtonMail/go-mime` to the latest version, which cleans up unneeded dependencies. And fix an issue with PGP/MIME messages with non standard encodings. - Sanitize strings returned in `MIMECallbacks.OnBody()` and `PlainMessage.GetString()`. Strings that have non utf8 characters will be sanitized to have the "character unknown" character : � instead. - Detached sign text messages with signature type text. Similarly, clearsigned messages now also use signature type text. - Leave trailing spaces of text messages intact (except for clearsigned messages, where the spec requires us to trim trailing spaces). Note that for backwards compatibility, when verifying detached signatures over text messages, the application will have to trim trailing spaces in order for the signature to verify, if it was created by a previous version of this library (using `crypto.NewPlainMessageFromString()`). ## [2.4.10] 2022-08-22 ### Changed - Updated underlying crypto library ## [2.4.9] 2022-08-19 ### Changed - Updated underlying crypto library and adjusted key clearing functions - Fixed typos in errors and comments ## [2.4.8] 2022-06-22 ### Changed - `SessionKey.Decrypt() and SessionKey.DecryptAndVerify()`, now support the decryption of AEAD encrypted data packets (packet type 20). ## [2.4.7] 2022-04-27 ### Changed - `DecryptMIMEMessage` will return the decrypted content in the `OnBody` callback, even when there's a signature verification error. That lets the caller decide whether they want to use the content with a warning or hard fail on signature errors. - Key generation functions no longer return an error if either the name or email is empty ## [2.4.6] 2022-03-25 ### Fixed - Update dependency `github.com/ProtonMail/go-mime`. It makes the parsing of MIME messages more flexible to messages with no specified charsets. - Fix the verification of PGP/MIME signature, the signature is now verified against the canonicalized content rather than the raw content. ## [2.4.5] 2022-03-01 ### Added - `(msg *PGPMessage) SplitMessage()` to split PGP messages, replacing `SeparateKeyAndData`. ### Changed - `SeparateKeyAndData` is now deprecated. ## [2.4.4] 2022-02-28 ### Changed - `SeparateKeyAndData` clones the returned byte slices to avoid overwriting. ## [2.4.3] 2022-02-24 ### Security - Fixed incorrect MDC parsing for session key decryption ### Changed - `SeparateKeyAndData` is now implemented in a more generic way, by checking for the location in the bytes of the last session key packet, then splitting the binary message after that point. ### Fixed - `SeparateKeyAndData` now correctly parses AEAD packets. - `(ap *AttachmentProcessor) Finish()` now returns encryption errors correctly. ## [2.4.2] 2022-01-13 ### Changed - Updated underlying crypto library and prevented AEAD messages from being created until the specification is stable ## [2.4.1] 2022-01-10 ### Fixed - Fixed bug with `NewPGPSplitMessageFromArmored(armored)` and `PGPMessage.SeparateKeyAndData()`. Those functions didn't parse AEAD encrypted messages correctly (eg messages encrypted with the latest versions of gnupg), resulting in a nil `DataPacket`. ## [2.4.0] 2021-12-21 ### Added - Function to verify a detached signature and get its creation time: ```go func (keyRing *KeyRing) GetVerifiedSignatureTimestamp(message *PlainMessage, signature *PGPSignature, verifyTime int64) (int64, error) ``` ### Changed - Updated the underlying crypto library ## [2.3.1] 2021-12-15 ### Fixed - Fix the verification of PGP/MIME message signatures: - Improve the handling of the dual verification status so that it is considered invalid if both embedded and PGP/MIME signatures are invalid. - start calling `callback.OnVerified(status int)` to communicate the status verification of the message. ## [2.3.0] 2021-11-15 ### Added - `Key.IsRevoked()` to check the revocation status of a key ### Security - Upgraded underlying crypto library to fix handling of revoked keys ## [2.2.5] 2021-11-11 ### Fixed - Protect the global `pgp` variable fields with a lock. - Unlock and lock dummy keys correctly ## [2.2.4] 2021-09-29 ### Fixed - Use the provided `verifyTime` instead of the current time when verifying embedded signatures. ## [2.2.3] 2021-09-21 ### Changed - Keys are now generated with ZLIB as preferred compression algorithm - Upgraded underlying crypto library ## [2.2.2] 2021-08-04 ### Added - `NewKeyFromEntity` to create a key from an openpgp entity ### Changed - Improved documentation for differences between text and binary messages ### Deprecated - `(key *Key) Check() (bool, error)` is now deprecated, all keys are now checked upon import from x/crypto ### Fixed - Dummy keys now show the correct locked/unlocked status ### Security - All keys are now checked on parsing from the underlying library ## [2.2.1] 2021-07-27 ### Changed - Changed the returned `SignatureVerificationError.Status` when trying to verify a message with no embedded signature. It used to return `constants.SIGNATURE_NO_VERIFIER` and now returns `constants.SIGNATURE_NOT_SIGNED`. This change impacts : - `func (sk *SessionKey) DecryptAndVerify(...)` - `func (msg *PlainMessageReader) VerifySignature(...)` - `func (keyRing *KeyRing) Decrypt(...)` - Improved error messages for failures in password protected message decryption ### Added - Helper to access the SignatureVerificationError explicitly when decrypting streams in mobile apps: ```go func VerifySignatureExplicit( reader *crypto.PlainMessageReader, ) (signatureVerificationError *crypto.SignatureVerificationError, err error) ``` ## [2.2.0] 2021-06-30 ### Added - Streaming API: - New structs: - `PlainMessageMetadata`: holds the metadata of a plain PGP message ```go type PlainMessageMetadata struct { IsBinary bool Filename string ModTime int64 } ``` - `PlainMessageReader` implements `Reader` and: ```go func (msg *PlainMessageReader) GetMetadata() *PlainMessageMetadata func (msg *PlainMessageReader) VerifySignature() (err error) ``` - `EncryptSplitResult` implements `WriteCloser` and: ```go func (res *EncryptSplitResult) GetKeyPacket() (keyPacket []byte, err error) ``` - Keyring methods: - Encrypt (and optionally sign) a message directly into a `Writer`: ```go func (keyRing *KeyRing) EncryptStream( pgpMessageWriter Writer, plainMessageMetadata *PlainMessageMetadata, signKeyRing *KeyRing, ) (plainMessageWriter WriteCloser, err error) ``` - Encrypt (and optionally sign) a message directly into a `Writer` (split keypacket and datapacket): ```go func (keyRing *KeyRing) EncryptSplitStream( dataPacketWriter Writer, plainMessageMetadata *PlainMessageMetadata, signKeyRing *KeyRing, ) (*EncryptSplitResult, error) ``` - Decrypt (and optionally verify) a message from a `Reader`: ```go func (keyRing *KeyRing) DecryptStream( message Reader, verifyKeyRing *KeyRing, verifyTime int64, ) (plainMessage *PlainMessageReader, err error) ``` N.B.: to verify the signature, you will need to call `plainMessage.VerifySignature()` after all the data has been read from `plainMessage`. - Decrypt (and optionally verify) a split message, getting the datapacket from a `Reader`: ```go func (keyRing *KeyRing) DecryptSplitStream( keypacket []byte, dataPacketReader Reader, verifyKeyRing *KeyRing, verifyTime int64, ) (plainMessage *PlainMessageReader, err error) ``` N.B.: to verify the signature, you will need to call `plainMessage.VerifySignature()` after all the data has been read from `plainMessage`. - Generate a detached signature from a `Reader`: ```go func (keyRing *KeyRing) SignDetachedStream(message Reader) (*PGPSignature, error) ``` - Verify a detached signature for a `Reader`: ```go func (keyRing *KeyRing) VerifyDetachedStream( message Reader, signature *PGPSignature, verifyTime int64, ) error ``` - Generate an encrypted detached signature from a `Reader`: ```go func (keyRing *KeyRing) SignDetachedEncryptedStream( message Reader, encryptionKeyRing *KeyRing, ) (encryptedSignature *PGPMessage, err error) ``` - Verify an encrypted detached signature for a `Reader`: ```go func (keyRing *KeyRing) VerifyDetachedEncryptedStream( message Reader, encryptedSignature *PGPMessage, decryptionKeyRing *KeyRing, verifyTime int64, ) error ``` - SessionKey methods: - Encrypt (and optionally sign) a message into a `Writer`: ```go func (sk *SessionKey) EncryptStream( dataPacketWriter Writer, plainMessageMetadata *PlainMessageMetadata, signKeyRing *KeyRing, ) (plainMessageWriter WriteCloser, err error) ``` - Decrypt (and optionally verify) a message from a `Reader`: ```go func (sk *SessionKey) DecryptStream( dataPacketReader Reader, verifyKeyRing *KeyRing, verifyTime int64, ) (plainMessage *PlainMessageReader, err error) ``` N.B.: to verify the signature, you will need to call `plainMessage.VerifySignature()` after all the data has been read from `plainMessage`. - Mobile apps helpers for `Reader` and `Writer`: Due to limitations of `gomobile`, mobile apps can't implement the `Reader` and `Writer` interfaces directly. - Implementing `Reader`: Apps should implement the interface: ```go type MobileReader interface { Read(max int) (result *MobileReadResult, err error) } type MobileReadResult struct { N int // N, The number of bytes read IsEOF bool // IsEOF, If true, then the reader has reached the end of the data to read. Data []byte // Data, the data that has been read } ``` And then wrap it with `Mobile2GoReader(mobileReader)` to turn it into a `Reader`. - Implementing `Writer`: The apps should implement the `Writer` interface directly, but still need to wrap the writer with `Mobile2GoWriter(mobileWriter)`. We also provide the `Mobile2GoWriterWithSHA256` if you want to compute the SHA256 hash of the written data. - Using a `Reader`: To use a reader returned by golang in mobile apps: you should wrap it with: - Android: `Go2AndroidReader(reader)`, implements the `Reader` interface, but returns `n == -1` instead of `err == io.EOF` - iOS: `Go2IOSReader(reader)`, implements `MobileReader`. - Using a `Writer`: you can use a writer returned by golang directly. ## [2.1.10] 2021-06-16 ### Fixed - Removed time interpolation via monotonic clock that can cause signatures in the future ## [2.1.9] 2021-05-12 ### Changed - Updated the underlying crypto library ## [2.1.8] 2021-04-27 ### Added - Key and KeyRing methods to check if a key/keyring can Encrypt or Verify ```go (key *Key) CanVerify() bool (key *Key) CanEncrypt() bool (keyRing *KeyRing) CanVerify() bool (keyRing *KeyRing) CanEncrypt() bool ``` - SessionKey methods to encrypt/decrypt and simultaneously sign/verify with an asymmetric key (embedded signature) ```go (sk *SessionKey) EncryptAndSign(message *PlainMessage, signKeyRing *KeyRing) ([]byte, error) (sk *SessionKey) DecryptAndVerify(dataPacket []byte, verifyKeyRing *KeyRing, verifyTime int64) (*PlainMessage, error) ``` - The mobile helper `DecryptSessionKeyExplicitVerify` to allow using session key decryption + verification operations via gomobile ## [2.1.7] 2021-03-30 ### Added - `ManualAttachmentProcessor`: a new kind of attachment processor where the caller has to first allocate a buffer large enough for the whole data packet to be written to. It can be created with ```processor, err := keyRing.NewManualAttachmentProcessor(estimatedSize, filename, dataBuffer)```. ### Fixed - Fix random failure in AES tests ### Changed - Updated the x/mobile fork and the build script to work with golang 1.16 ## [2.1.6] 2021-03-17 ### Added - Decryption tests for attachments ### Fixed - Armoring headers for public or private keys - Session key decoding on invalid keys - Support for multiple embedded signatures (not nested) ### Security - Updated the underlying crypto library ## [2.1.5] 2021-02-19 ## Changed - Removed an unnecessary cloning in the attachment processor, to perform better in low memory settings ## [2.1.4] 2021-01-08 ### Added - Methods for generating an verifying encrypted detached signatures ```go (signingKeyRing *KeyRing) SignDetachedEncrypted(message *PlainMessage, encryptionKeyRing *KeyRing) (encryptedSignature *PGPMessage, err error) (verifyingKeyRing *KeyRing) VerifyDetachedEncrypted(message *PlainMessage, encryptedSignature *PGPMessage, decryptionKeyRing *KeyRing, verifyTime int64) error ``` ## [2.1.3] 2020-12-09 ### Added - `helper.FreeOSMemory()` to explicitly call the GC and release the memory to the OS ### Changed - Users of the library no longer need a `replace` directive for x/crypto - Added new calls to `runtime.GC()` in the low memory attachment processor - Reduced attachment memory allocation ## [2.1.2] 2020-12-01 ### Added - `SetKeyGenerationOffset` to add an offset in key generation time and prevent not-yet-valid keys. ### Changed - Improved canonicalization performance ## [2.1.1] 2020-11-16 ### Changed - Session key decryption now considers multiple key packets ### Fixed - Improved key parsing error handling ## [2.1.0] 2020-11-04 ### Security - Updated underlying crypto library ### Added - Key Armoring with custom headers ```go (key *Key) ArmorWithCustomHeaders(comment, version string) (string, error) (key *Key) GetArmoredPublicKeyWithCustomHeaders(comment, version string) (string, error) ``` - Message armoring with custom headers ```go (msg *PGPMessage) GetArmoredWithCustomHeaders(comment, version string) (string, error) ``` - Extraction of encryption key IDs from a PGP message, i.e. the IDs of the keys used in the encryption of the session key ```go (msg *PGPMessage) GetEncryptionKeyIDs() ([]uint64, bool) (msg *PGPMessage) GetHexEncryptionKeyIDs() ([]uint64, bool) ``` - Extraction of signing key IDs from a PGP message, i.e. the IDs of the keys used in the signature of the message (of all the readable, unencrypted signature packets) ```go (msg *PGPMessage) GetSignatureKeyIDs() ([]uint64, bool) (msg *PGPMessage) GetHexSignatureKeyIDs() ([]string, bool) ``` - Getter for the x/crypto Entity (internal components of an OpenPGP key) from Key struct ```go (key *Key) GetEntity() *openpgp.Entity ``` - Helpers for binary message encryption and decryption ```go EncryptBinaryMessageArmored(key string, data []byte) (string, error) DecryptBinaryMessageArmored(privateKey string, passphrase []byte, ciphertext string) ([]byte, error) ``` - Method to derive a public key object from a private key ```go (key *Key) ToPublic() (publicKey *Key, err error) ``` - Helpers to handle encryption (both with armored and unarmored cipher) + encrypted detached signatures in one call. ```go EncryptSignArmoredDetached( publicKey, privateKey string, passphrase, plainData []byte, ) (ciphertextArmored, encryptedSignatureArmored string, err error) DecryptVerifyArmoredDetached( publicKey, privateKey string, passphrase []byte, ciphertextArmored string, encryptedSignatureArmored string, ) (plainData []byte, err error) ``` ```go EncryptSignBinaryDetached( publicKey, privateKey string, passphrase, plainData []byte, ) (encryptedData []byte, encryptedSignatureArmored string, err error) DecryptVerifyBinaryDetached( publicKey, privateKey string, passphrase []byte, encryptedData []byte, encryptedSignatureArmored string, ) (plainData []byte, err error) ``` - Wrappers for `EncryptSignArmoredDetached` and `EncryptSignBinaryDetached` helpers, to be usable with gomobile (that doesn't support multiple return values). These wrappers return custom structs instead. ```go type EncryptSignArmoredDetachedMobileResult struct { CiphertextArmored, EncryptedSignatureArmored string } EncryptSignArmoredDetachedMobile( publicKey, privateKey string, passphrase, plainData []byte, ) (wrappedTuple *EncryptSignArmoredDetachedMobileResult, err error) ``` ```go type EncryptSignBinaryDetachedMobileResult struct { EncryptedData []byte EncryptedSignatureArmored string } EncryptSignBinaryDetachedMobile( publicKey, privateKey string, passphrase, plainData []byte, ) (wrappedTuple *EncryptSignBinaryDetachedMobileResult, err error) ``` - helpers to encrypt/decrypt session keys with armored keys: ```go EncryptSessionKey( publicKey string, sessionKey *crypto.SessionKey, ) (encryptedSessionKey []byte, err error) DecryptSessionKey( privateKey string, passphrase, encryptedSessionKey []byte, ) (sessionKey *crypto.SessionKey, err error) ``` - helpers to encrypt/decrypt binary files with armored keys: ```go EncryptAttachmentWithKey( publicKey string, filename string, plainData []byte, ) (message *crypto.PGPSplitMessage, err error) DecryptAttachmentWithKey( privateKey string, passphrase, keyPacket, dataPacket []byte, ) (attachment []byte, err error) ``` - `NewPlainMessageFromFile` Function to create new `PlainMessage`s with a filename: ```go NewPlainMessageFromFile(data []byte, filename string, modTime int) *PlainMessage ``` - `GetFilename` to get the filename from a message: ```go (msg *PlainMessage) GetFilename() string ``` - `GetModTime` to get the modification time of a file ```go (msg *PlainMessage) GetModTime() uint32 ``` - `EncryptWithCompression` to encrypt specifying a compression for asymmetric and session keys ```go (keyRing *KeyRing) EncryptWithCompression(message *PlainMessage, privateKey *KeyRing) (*PGPMessage, error) (sk *SessionKey) EncryptWithCompression(message *PlainMessage) ([]byte, error) ``` ### Changed - Improved key and message armoring testing - `EncryptSessionKey` now creates encrypted key packets for each valid encryption key in the provided keyring. Returns a byte slice with all the concatenated key packets. - Use aes256 cipher for password-encrypted messages. - The helpers `EncryptSignMessageArmored`, `DecryptVerifyMessageArmored`, `DecryptVerifyAttachment`, and`DecryptBinaryMessageArmored` now accept private keys as public keys and perform automatic casting if the keys are locked. - The `PlainMessage` struct now contains the fields `Filename` (string) and `Time` (uint32) - All the Decrypt* functions return the filename, type, and time specified in the encrypted message - Improved error wrapping and management - CI has been moved from travis to Actions, with automated artifacts build ### Fixed - Public key armoring headers - `EncryptSessionKey` throws an error when invalid encryption keys are provided - Session keys' size is now checked against the expected value to prevent panics - Hex Key IDs returned from `(key *Key) GetHexKeyID() string` are now correctly padded - Avoid panics in `(msg *PGPMessage) GetEncryptionKeyIDs() ([]uint64, bool)` by breaking the packet.next cycle on specific packet types - Prevent the server time from going backwards in `UpdateTime` - Avoid panicking when messages with mixed symmetric/asymmetric key packets are decrypted with a password ## [2.0.1] - 2020-05-01 ### Security - Updated underlying crypto library - Improved memory zeroing in helpers ### Fixed - Fixed garbage collection issues when compiled on gomobile, by copying byte slices - Password encrypted binary files now have the correct flags - Fixed missing space in `Hash` header of cleartext messages - Fixed tests `TestMultipleKeyMessageEncryption` and `TestSymmetricKeyPacket` ## Changed - Providing empty passphrase does no longer throw an error when unlocking an unencrypted private key - Improved code linter ### Added - SHA256 fingerprint support ```go (key *Key) GetSHA256Fingerprints() (fingerprints []string) // Helper GetSHA256Fingerprints(publicKey string) ([]string, error) // Helper, mobile only, returns fingerprints encoded as JSON GetJsonSHA256Fingerprints(publicKey string) ([]byte, error) ``` ## [2.0.0] - 2020-01-06 Since the open-sourcing of the library in May the API has been updated, listening to internal and external feedback, in order to have a flexible library, that can be used in a simple settings, with batteries included, or by more advanced users that might want to interact directly with the inner structure of the PGP messages and keys. It allows direct interaction with keys and keyrings, passphrases, as well as session keys. It is designed with gomobile users in mind, so that they can use the full power of the library, without having to rely on a further wrapper. This version comes with some design improvements, in particular the introduction of keys ### Security - Dropped the use of strings for secrets - New key checking functions - Clear memory after use, in an attempt to reduce leftover secrets in RAM. - Improved testing, in this and the underlying crypto library ### Fixed - `KeyRing`s can now only be unencrypted, removing the problem of mixed encrypted/decrypted keyring, that caused keys not to be recognised. - Explicit key decryption and encryption. - Underlying crypto library update. - Underlying MIME library update. - Fixed ECC critical bugs. - Removed gopenpgp/pmcrypto object as it could create multiple globals. Methods are now static on the crypto object. ### Removed - `Signature` struct - `Signature#KeyRing` function - `Signature#IsBy` function - `pmKeyObject` struct - `encodedLength` function, internal and and unused - `EncryptCore` is now internal. - `RandomTokenWith`, `RandomToken` now takes a size - In the `KeyRing` struct: - `KeyRing#GetEntities`, entities are handled by the lib - `KeyRing#GetSigningEntity`, has been made internal - `KeyRing#Unlock`, the unlocking functionalities are on now on the key object - `BuildKeyRingNoError`, `BuildKeyRingArmored`, `BuildKeyRing` use `NewKey` or `NewKeyFromArmored` and handle errors then join them into KeyRings. - `ReadKeyRing`, `ReadArmoredKeyRing`, use `NewKeyFromArmoredReader` or `NewKeyFromReader`. - `UnmarshalJSON`, the interface to unmarshal JSON is not relevant to this library. ### Added - `Key` struct, to store, import (unserialize) and export (serialize) keys. ```go // Key contains a single private or public key type Key struct { // PGP entities in this keyring. entity *openpgp.Entity } // With the functions NewKeyFromArmoredReader(r io.Reader) (key *Key, err error) NewKeyFromReader(r io.Reader) (key *Key, err error) NewKey(binKeys []byte) (key *Key, err error) NewKeyFromArmored(armored string) (key *Key, err error) GenerateKey(name, email string, keyType string, bits int) (*Key, error) GenerateRSAKeyWithPrimes(name, email string, bits int, primeone, primetwo, primethree, primefour []byte) (*Key, error) (key *Key) Clone() (*Key, error) (key *Key) Lock(passphrase []byte) (*Key, error) (key *Key) Unlock(passphrase []byte) (*Key, error) (key *Key) Serialize() ([]byte, error) (key *Key) Armor() (string, error) (key *Key) GetArmoredPublicKey() (s string, err error) (key *Key) GetPublicKey() (b []byte, err error) (key *Key) IsExpired() bool (key *Key) IsPrivate() bool (key *Key) IsLocked() (bool, error) (key *Key) IsUnlocked() (bool, error) (key *Key) Check() (bool, error) (key *Key) PrintFingerprints() (key *Key) GetHexKeyID() string (key *Key) GetKeyID() uint64 (key *Key) GetFingerprint() string (key *Key) ClearPrivateParams() (ok bool) ``` - In the `KeyRing` object: ```go NewKeyRing(key *Key) (*KeyRing, error) (keyRing *KeyRing) AddKey(key *Key) error (keyRing *KeyRing) GetKeys() []*Key (keyRing *KeyRing) GetKey(n int) (*Key, error) (keyRing *KeyRing) CountEntities() int (keyRing *KeyRing) CountDecryptionEntities() int (keyRing *KeyRing) GetIdentities() []*Identity (keyRing *KeyRing) FirstKey() (*KeyRing, error) (keyRing *KeyRing) Clone() (*KeyRing, error) (keyRing *KeyRing) ClearPrivateParams() ``` - `PlainMessage` struct, to store un-encrypted messages ```go // PlainMessage stores a plain text / unencrypted message. type PlainMessage struct { // The content of the message Data []byte // if the content is text or binary TextType bool } // With the functions NewPlainMessage(data []byte) *PlainMessage NewPlainMessageFromString(text string) *PlainMessage (msg *PlainMessage) GetBinary() (msg *PlainMessage) GetString() (msg *PlainMessage) GetBase64() (msg *PlainMessage) NewReader() (msg *PlainMessage) IsText() (msg *PlainMessage) IsBinary() ``` - `PGPMessage` struct, to store encrypted PGP messages ```go // PGPMessage stores a PGP-encrypted message. type PGPMessage struct { // The content of the message Data []byte } // With the functions NewPGPMessage(data []byte) *PGPMessage NewPGPMessageFromArmored(armored string) (*PGPMessage, error) (msg *PGPMessage) GetBinary() []byte (msg *PGPMessage) NewReader() io.Reader (msg *PGPMessage) GetArmored() (string, error) (msg *PGPMessage) SeparateKeyAndData(estimatedLength, garbageCollector int) (outSplit *PGPSplitMessage, err error) ``` - `PGPSignature` struct, to store detached PGP signatures ```go // PGPSignature stores a PGP-encoded detached signature. type PGPSignature struct { // The content of the message Data []byte } // With the functions NewPGPSignature(data []byte) *PGPSignature NewPGPSignatureFromArmored(armored string) (*PGPSignature, error) (msg *PGPSignature) GetBinary() []byte (msg *PGPSignature) GetArmored() (string, error) ``` - `SignatureVerificationError` struct, to separate signature verification errors from decryption errors ```go // SignatureVerificationError is returned from Decrypt and VerifyDetached functions when signature verification fails type SignatureVerificationError struct { Status int Message string } ``` ### Changed - `IsKeyExpiredBin` has been renamed to `IsKeyExpired` - `IsKeyExpired` has been renamed to `IsArmoredKeyExpired` - `CheckKey` has been renamed to `PrintFingerprints` - `KeyRing#ArmoredPublicKeyString` has been renamed to `KeyRing#GetArmoredPublicKey` - `KeyRing#KeyIds` has been renamed to `KeyRing#GetKeyIDs` - `GetTimeUnix` was renamed to `GetUnixTime` - `EncryptedSplit` has been changed to `PGPSplitMessage` ```go models.EncryptedSplit struct { DataPacket []byte KeyPacket []byte Algo string } // Is now crypto.PGPSplitMessage struct { DataPacket []byte KeyPacket []byte } // With the functions NewPGPSplitMessage(keyPacket []byte, dataPacket []byte) *PGPSplitMessage NewPGPSplitMessageFromArmored(encrypted string) (*PGPSplitMessage, error) (msg *PGPSplitMessage) GetBinaryDataPacket() []byte (msg *PGPSplitMessage) GetBinaryKeyPacket() []byte (msg *PGPSplitMessage) GetBinary() []byte (msg *PGPSplitMessage) GetArmored() (string, error) ``` - `DecryptSignedVerify` has been changed to `ExplicitVerifyMessage` ```go models.DecryptSignedVerify struct { //clear text Plaintext string //bitmask verify status : 0 Verify int //error message if verify failed Message string } // Is now // ExplicitVerifyMessage contains explicitly the signature verification error, for gomobile users type ExplicitVerifyMessage struct { Message *crypto.PlainMessage SignatureVerificationError *crypto.SignatureVerificationError } // With the new helper DecryptExplicitVerify (pgpMessage *crypto.PGPMessage, privateKeyRing, publicKeyRing *crypto.KeyRing, verifyTime int64) (*ExplicitVerifyMessage, error) ``` - `SignedString` has been changed to `ClearTextMessage` ```go // SignedString wraps string with Signature type SignedString struct { String string Signed *Signature } // Is now // ClearTextMessage, split signed clear text message container type ClearTextMessage struct { Data []byte Signature []byte } // With the functions NewClearTextMessage(data []byte, signature []byte) *ClearTextMessage NewClearTextMessageFromArmored(signedMessage string) (*ClearTextMessage, error) (msg *ClearTextMessage) GetBinary() []byte (msg *ClearTextMessage) GetString() string (msg *ClearTextMessage) GetBinarySignature() []byte (msg *ClearTextMessage) GetArmored() (string, error) ``` - `SymmetricKey` has been renamed to `SessionKey` ```go // SessionKey stores a decrypted session key. type SessionKey struct { // The decrypted binary session key. Key []byte // The symmetric encryption algorithm used with this key. Algo string } // With the functions NewSessionKeyFromToken(token []byte, algo string) *SessionKey GenerateSessionKey() (*SessionKey, error) GenerateSessionKeyAlgo(algo string) (sk *SessionKey, err error) (sk *SessionKey) GetCipherFunc() packet.CipherFunction (sk *SessionKey) GetBase64Key() string (sk *SessionKey) Encrypt(message *PlainMessage) ([]byte, error) (sk *SessionKey) Decrypt(dataPacket []byte) (*PlainMessage, error) (sk *SessionKey) Clear() (ok bool) ``` - `ReadClearSignedMessage` moved to crypto package and renamed to `NewClearTextMessageFromArmored`. Changed to return `ClearTextMessage`. ```go ReadClearSignedMessage(signedMessage string) (string, error) // Is now NewClearTextMessageFromArmored(signedMessage string) (*ClearTextMessage, error) // In addition, were added: NewClearTextMessage(data []byte, signature []byte) *ClearTextMessage (msg *ClearTextMessage) GetBinary() []byte (msg *ClearTextMessage) GetString() string (msg *ClearTextMessage) GetBinarySignature() []byte (msg *ClearTextMessage) GetArmored() (string, error) // As helpers were added: SignCleartextMessageArmored(privateKey string, passphrase []byte, text string) (string, error) VerifyCleartextMessageArmored(publicKey, armored string, verifyTime int64) (string, error) SignCleartextMessage(keyRing *crypto.KeyRing, text string) (string, error) VerifyCleartextMessage(keyRing *crypto.KeyRing, armored string, verifyTime int64) (string, error) ``` - `EncryptAttachment`'s parameters are changed to messages. ```go (pm *PmCrypto) EncryptAttachment(plainData []byte, fileName string, publicKey *KeyRing) (*models.EncryptedSplit, error) // Is now (keyRing *KeyRing) EncryptAttachment(message *PlainMessage, fileName string) (*PGPSplitMessage, error) // As a helper was added: EncryptSignAttachment(publicKey, privateKey string, passphrase []byte, fileName string, plainData []byte) (keyPacket, dataPacket, signature []byte, err error) ``` - `DecryptAttachment` has been moved to KeyRing struct (like `EncryptAttachment`) ```go (pm *PmCrypto) DecryptAttachment(keyPacket []byte, dataPacket []byte, kr *KeyRing, passphrase string) ([]byte, error) // Is now (keyRing *KeyRing) DecryptAttachment(message *PGPSplitMessage) (*PlainMessage, error) // As a helper was added: DecryptVerifyAttachment(publicKey, privateKey string, passphrase, keyPacket, dataPacket []byte, armoredSignature string) (plainData []byte, err error) ``` - `EncryptAttachmentLowMemory` was renamed to `NewLowMemoryAttachmentProcessor`. ```go (pm *PmCrypto) EncryptAttachmentLowMemory(estimatedSize int, fileName string, publicKey *KeyRing) (*AttachmentProcessor, error) // Is now (keyRing *KeyRing) NewLowMemoryAttachmentProcessor(estimatedSize int, fileName string) (*AttachmentProcessor, error) ``` - `SplitArmor` was renamed to `NewPGPSplitMessageFromArmored` and the model changed. ```go SplitArmor(encrypted string) (*models.EncryptedSplit, error) // Is now NewPGPSplitMessageFromArmored(encrypted string) (*PGPSplitMessage, error) ``` - `DecryptAttKey` was renamed to `DecryptSessionKey` and the parameter keypacket changed to `[]byte` as it's binary, not armored. ```go DecryptAttKey(kr *KeyRing, keyPacket string) (key *SymmetricKey, err error): // Is now (keyRing *KeyRing) DecryptSessionKey(keyPacket []byte) (*SessionKey, error) ``` - `SetKey` has been renamed to `EncryptSessionKey`, and the keypacket return value changed to `[]byte`. ```go SetKey(kr *KeyRing, symKey *SymmetricKey) (packets string, err error): // Is now (keyRing *KeyRing) EncryptSessionKey(sessionSplit *SessionKey) ([]byte, error) ``` - `SeparateKeyAndData` has been split in two different function, as it did not only separate the data, but when provided a KeyRing decrypted the session key too. ```go SeparateKeyAndData(kr *KeyRing, r io.Reader, estimatedLength int, garbageCollector int) (outSplit *models.EncryptedSplit, err error): // Is now the conjunction of the following function: // To separate key and data (msg *PGPMessage) SeparateKeyAndData(estimatedLength, garbageCollector int) (outSplit *PGPSplitMessage, err error) // To decrypt the SessionKey (keyRing *KeyRing) DecryptSessionKey(keyPacket []byte) (*SessionKey, error) ``` - `EncryptSymmetric` has been changed, now the procedure is split in two parts: `Encrypt` and `SeparateKeyAndData` ```go (kr *KeyRing) EncryptSymmetric(textToEncrypt string, canonicalizeText bool) (outSplit *models.EncryptedSplit, err error): // Is now the conjunction of the following function: // To encrypt (keyRing *KeyRing) Encrypt(message *PlainMessage, privateKey *KeyRing) (*PGPMessage, error) // To separate key and data (msg *PGPMessage) SeparateKeyAndData(estimatedLength, garbageCollector int) (outSplit *PGPSplitMessage, err error) ``` - `GenerateKey`'s signature has been altered: - It now returns a `Key` struct - `userName` and `domain` are now joined in `email`, the `name` parameter was added (To emulate the old behaviour `name = email = userName + "@" + domain`). ```go (pm *PmCrypto) GenerateKey(userName, domain, passphrase, keyType string, bits int) (string, error) : // Is now GenerateKey(name, email string, keyType string, bits int) (*Key, error) // As a helper was added: GenerateKey(name, email string, passphrase []byte, keyType string, bits int) (string, error) ``` - `GenerateRSAKeyWithPrimes`'s signature has been altered: - It now returns a `Key` struct - `userName` and `domain` are now joined in `email`, the `name` parameter was added (To emulate the old behaviour `name = email = userName + "@" + domain`). ```go (pm *PmCrypto) GenerateRSAKeyWithPrimes(userName, domain, passphrase, keyType string, bits int, prime1, prime2, prime3, prime4 []byte) (string, error): GenerateRSAKeyWithPrimes(name, email string, bits int, primeone, primetwo, primethree, primefour []byte,) (*Key, error) ``` - `Encrypt`, `EncryptArmored`, `EncryptString`, `EncryptMessage` functions have been changed to return and accept messages. ```go (kr *KeyRing) Encrypt(w io.Writer, sign *KeyRing, filename string, canonicalizeText bool) (io.WriteCloser, error) // Is now (keyRing *KeyRing) Encrypt(message *PlainMessage, privateKey *KeyRing) (*PGPMessage, error) // As a helpers were added: EncryptMessageArmored(publicKey, plaintext string) (ciphertext string, err error) EncryptSignMessageArmored(publicKey, privateKey string, passphrase []byte, plaintext string) (ciphertext string, err error) { ``` - `Decrypt`, `DecryptArmored`, `DecryptString`, `DecryptMessage`, `DecryptMessageVerify`, and `DecryptMessageStringKey` functions have been changed to return and accept messages (Same as Encrypt*). If signature verification fails they will return a SignatureVerificationError. ```go (kr *KeyRing) DecryptString(encrypted string) (SignedString, error) // Is now (keyRing *KeyRing) Decrypt(message *PGPMessage, verifyKey *KeyRing, verifyTime int64) (*PlainMessage, error) // As a helpers were added: DecryptMessageArmored(privateKey string, passphrase []byte, ciphertext string) (plaintext string, err error) DecryptVerifyMessageArmored(publicKey, privateKey string, passphrase []byte, ciphertext string) (plaintext string, err error) DecryptExplicitVerify(pgpMessage *crypto.PGPMessage, privateKeyRing, publicKeyRing *crypto.KeyRing, verifyTime int64) (*ExplicitVerifyMessage, error) { ``` - `DecryptStringIfNeeded` has been replaced with `IsPGPMessage` + `Decrypt*`. ```go (kr *KeyRing) DecryptStringIfNeeded(data string) (decrypted string, err error) // Is now the conjunction of the following function: // To check if the data is a PGP message IsPGPMessage(data string) bool // To decrypt (keyRing *KeyRing) Decrypt(message *PGPMessage, verifyKey *KeyRing, verifyTime int64) (*PlainMessage, error) ``` - `SignString` and `DetachedSign` have been replaced by signing methods. ```go (kr *KeyRing) SignString(message string, canonicalizeText bool) (signed string, err error) (kr *KeyRing) DetachedSign(w io.Writer, toSign io.Reader, canonicalizeText bool, armored bool) // Are now (keyRing *KeyRing) SignDetached(message *PlainMessage) (*PGPSignature, error) ``` - `VerifyString` has been altered in the same way as as signing. Returns SignatureVerificationError if the verification fails. ```go (kr *KeyRing) VerifyString(message, signature string, sign *KeyRing) (err error) // Is now (keyRing *KeyRing) VerifyDetached(message *PlainMessage, signature *PGPSignature, verifyTime int64) error ``` - `EncryptMessageWithPassword` uses AES-256 instead of AES-128, and has a new signature. ```go (pm *PmCrypto) EncryptMessageWithPassword(plaintext string, password string) (string, error) // Is now EncryptMessageWithPassword(message *PlainMessage, password []byte) (*PGPMessage, error) // As a helper was added: EncryptMessageWithPassword(password []byte, plaintext string) (ciphertext string, err error) ``` - `DecryptMessageWithPassword` accepts all symmetric algorithms known to the lib, and has a new signature ```go (pm *PmCrypto) DecryptMessageWithPassword(encrypted string, password string) (string, error) // Is now DecryptMessageWithPassword(message *PGPMessage, password []byte) (*PlainMessage, error) // As a helper was added: DecryptMessageWithPassword(password []byte, ciphertext string) (plaintext string, err error) ``` - `DecryptMIMEMessage` was moved to `KeyRing`, and the parameters transformed to messages ```go (pm *PmCrypto) DecryptMIMEMessage(encryptedText string, verifierKey *KeyRing, privateKeyRing *KeyRing, passphrase string, callbacks MIMECallbacks, verifyTime int64): // Is now (keyRing *KeyRing) DecryptMIMEMessage(message *PGPMessage, verifyKey *KeyRing, callbacks MIMECallbacks, verifyTime int64) ``` - `RandomToken` now takes a size ```go (pm *PmCrypto) RandomToken() ([]byte, error) // Is now RandomToken(size int) ([]byte, error) ``` - `GetSessionFromKeyPacket` was changed to `DecryptSessionKey`. ```go (pm *PmCrypto) GetSessionFromKeyPacket(keyPackage []byte, privateKey *KeyRing, passphrase string) (*SymmetricKey, error) // Is now (keyRing *KeyRing) DecryptSessionKey(keyPacket []byte) (*SessionKey, error) ``` - `KeyPacketWithPublicKey` and `KeyPacketWithPublicKeyBin` have been merged to `EncryptSessionKey`. ```go (pm *PmCrypto) KeyPacketWithPublicKey(sessionSplit *SymmetricKey, publicKey string) ([]byte, error) (pm *PmCrypto) KeyPacketWithPublicKeyBin(sessionSplit *SymmetricKey, publicKey []byte) ([]byte, error) (keyRing *KeyRing) EncryptSessionKey(sk *SessionKey) ([]byte, error) ``` - `GetSessionFromSymmetricPacket` was renamed to `DecryptSessionKeyWithPassword`. ```go (pm *PmCrypto) GetSessionFromSymmetricPacket(keyPackage []byte, password string) (*SymmetricKey, error) // Is now DecryptSessionKeyWithPassword(keyPacket, password []byte) (*SessionKey, error) ``` - `SymmetricKeyPacketWithPassword` has been renamed to `EncryptSessionKeyWithPassword` ```go (pm *PmCrypto) SymmetricKeyPacketWithPassword(sessionSplit *SymmetricKey, password string) ([]byte, error): EncryptSessionKeyWithPassword(sk *SessionKey, password []byte]) ([]byte, error) ``` - `SignTextDetached` and `SignBinDetached` have been changed to `SignDetached` ```go (pm *PmCrypto) SignTextDetached(plaintext string, privateKey *KeyRing, passphrase string, trim bool) (string, error) (pm *PmCrypto) SignBinDetached(plainData []byte, privateKey *KeyRing, passphrase string) (string, error) // Are now (keyRing *KeyRing) SignDetached(message *PlainMessage) (*PGPSignature, error) // As helpers were added: SignCleartextMessage(keyRing *crypto.KeyRing, text string) (string, error) SignCleartextMessageArmored(privateKey string, passphrase []byte, text string) (string, error) ``` - `VerifyTextSignDetachedBinKey` and `VerifyBinSignDetachedBinKey` have been changed to `Verify`. ```go (pm *PmCrypto) VerifyTextSignDetachedBinKey(signature string, plaintext string, publicKey *KeyRing, verifyTime int64) (bool, error): (pm *PmCrypto) VerifyBinSignDetachedBinKey(signature string, plainData []byte, publicKey *KeyRing, verifyTime int64) (bool, error) // Are now (keyRing *KeyRing) VerifyDetached(message *PlainMessage, signature *PGPSignature, verifyTime int64) error // As helpers were added: VerifyCleartextMessage(keyRing *crypto.KeyRing, armored string, verifyTime int64) (string, error) VerifyCleartextMessageArmored(publicKey, armored string, verifyTime int64) (string, error) ``` ## [1.0.0] - 2019-05-15 Initial release, opensourcing of the internal library `PMCrypto`, and subsequent renaming to `gopenpgp` golang-github-protonmail-gopenpgp-v3-3.1.0/LICENSE000066400000000000000000000020751472137411600216060ustar00rootroot00000000000000(The MIT License) Copyright (c) 2019 Proton Technologies AG Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. golang-github-protonmail-gopenpgp-v3-3.1.0/README.md000066400000000000000000000333361472137411600220640ustar00rootroot00000000000000# GopenPGP V3 [![Go Report Card](https://goreportcard.com/badge/github.com/ProtonMail/gopenpgp/v3)](https://goreportcard.com/report/github.com/ProtonMail/gopenpgp/v3) [![GoDoc](https://godoc.org/github.com/ProtonMail/gopenpgp/v3?status.svg)](https://godoc.org/github.com/ProtonMail/gopenpgp/v3) GopenPGP V3 is a high-level OpenPGP library built on top of [a fork of the golang crypto library](https://github.com/ProtonMail/go-crypto). **Table of Contents** - [GopenPGP V3](#gopenpgp-v3) - [GopenPGP V2 support](#gopenpgp-v2-support) - [Download/Install](#downloadinstall) - [Documentation](#documentation) - [Examples](#examples) - [Encrypt / Decrypt with a password](#encrypt--decrypt-with-a-password) - [Encrypt / Decrypt with PGP keys](#encrypt--decrypt-with-pgp-keys) - [Generate key](#generate-key) - [Detached and inline signatures](#detached-and-inline-signatures) - [Cleartext signed messages](#cleartext-signed-messages) - [Encrypt with different outputs](#encrypt-with-different-outputs) - [Using with Go Mobile](#using-with-go-mobile) ## GopenPGP V2 support While GopenPGP V3 introduces a new API with significant enhancements, it is not backward compatible with GopenPGP V2. Although we recommend upgrading to V3 for the latest features and improvements, we continue to support GopenPGP V2. Our support includes ongoing bug fixes and minor feature updates to ensure stability and functionality for existing users. GopenPGP V2 can be accessed/modified via the [v2 branch of this repository](https://github.com/ProtonMail/gopenpgp/tree/v2). ## Download/Install To use GopenPGP with [Go Modules](https://github.com/golang/go/wiki/Modules) just run ``` go get github.com/ProtonMail/gopenpgp/v3 ``` in your project folder. Then, your code can include it as follows: ```go package main import ( "fmt" "github.com/ProtonMail/gopenpgp/v3/crypto" ) func main() { pgp := crypto.PGP() } ``` ## Documentation A full overview of the API can be found here: https://pkg.go.dev/github.com/ProtonMail/gopenpgp/v3. ## Examples A file of runnable examples can be found in [crypto_example_test.go](crypto/crypto_example_test.go). ### Encrypt / Decrypt with a password ```go import "github.com/ProtonMail/gopenpgp/v3/crypto" password := []byte("hunter2") pgp := crypto.PGP() // Encrypt data with a password encHandle, err := pgp.Encryption().Password(password).New() pgpMessage, err := encHandle.Encrypt([]byte("my message")) armored, err := pgpMessage.ArmorBytes() // Decrypt data with a password decHandle, err := pgp.Decryption().Password(password).New() decrypted, err := decHandle.Decrypt(armored, crypto.Armor) myMessage := decrypted.Bytes() ``` To encrypt with the [latest OpenPGP standard (RFC 9580)](https://www.rfc-editor.org/rfc/rfc9580.html): ```go import "github.com/ProtonMail/gopenpgp/v3/profile" // Use the latest OpenPGP standard (RFC 9580). pgp := crypto.PGPWithProfile(profile.RFC9580()) // The RFC9580 profile uses Argon2 for protecting encrypted keys and // messages encrypted using a passphrase, and uses AEAD for encryption // (AES-256, OCB mode). // Encrypt/Decrypt data with a password ... // See code snippet above. ``` Use a custom or preset profile: ```go import "github.com/ProtonMail/gopenpgp/v3/profile" // RFC4880 profile pgp4880 := crypto.PGPWithProfile(profile.RFC4880()) // RFC9580 profile pgpCryptoRefresh := crypto.PGPWithProfile(profile.RFC9580()) ``` ### Encrypt / Decrypt with PGP keys ```go // Put keys in backtick (``) to avoid errors caused by spaces or tabs const pubkey = `-----BEGIN PGP PUBLIC KEY BLOCK----- ... -----END PGP PUBLIC KEY BLOCK-----` const privkey = `-----BEGIN PGP PRIVATE KEY BLOCK----- ... -----END PGP PRIVATE KEY BLOCK-----` // Encrypted private key const passphrase = []byte(`the passphrase of the private key`) // Passphrase of the privKey publicKey, err := crypto.NewKeyFromArmored(pubkey) privateKey, err := crypto.NewPrivateKeyFromArmored(privkey, passphrase) pgp := crypto.PGP() // Encrypt plaintext message using a public key encHandle, err := pgp.Encryption().Recipient(publicKey).New() pgpMessage, err := encHandle.Encrypt([]byte("my message")) armored, err := pgpMessage.ArmorBytes() // Decrypt armored encrypted message using the private key and obtain the plaintext decHandle, err := pgp.Decryption().DecryptionKey(privateKey).New() decrypted, err := decHandle.Decrypt(armored, crypto.Armor) myMessage := decrypted.Bytes() decHandle.ClearPrivateParams() ``` With signatures: ```go pgp := crypto.PGP() aliceKeyPriv, err := pgp.KeyGeneration(). AddUserId("alice", "alice@alice.com"). New(). GenerateKey() aliceKeyPub, err := aliceKeyPriv.ToPublic() bobKeyPriv, err := pgp.KeyGeneration(). AddUserId("bob", "bob@bob.com"). New(). GenerateKey() bobKeyPub, err := bobKeyPriv.ToPublic() // Encrypt and sign plaintext message from alice to bob encHandle, err := pgp.Encryption(). Recipient(bobKeyPub). SigningKey(aliceKeyPriv). New() pgpMessage, err := encHandle.Encrypt([]byte("my message")) armored, err := pgpMessage.ArmorBytes() // Decrypt armored encrypted message using the private key and obtain plain text decHandle, err := pgp.Decryption(). DecryptionKey(bobKeyPriv). VerificationKey(aliceKeyPub). New() decrypted, err := decHandle.Decrypt(armored, crypto.Armor) if sigErr := decrypted.SignatureError(); sigErr != nil { // Signature verification failed with sigErr } myMessage := decrypted.Bytes() encHandle.ClearPrivateParams() decHandle.ClearPrivateParams() ``` Encrypt towards multiple recipients: ```go recipients, err := crypto.NewKeyRing(bobKeyPub) err = recipients.AddKey(carolKeyPub) // encrypt plain text message using a public key encHandle, err := pgp.Encryption(). Recipients(recipients). SigningKey(aliceKeyPriv). New() pgpMessage, err := encHandle.Encrypt([]byte("my message")) armored, err := pgpMessage.ArmorBytes() encHandle.ClearPrivateParams() ``` Encrypt towards an (anonymous) recipient: ```go //... // The key fingerprint of bob's key is visible in the key packet and // is included in the signature's intended recipient list. // The key fingerprint of carols's key is not visible in the key packet ("anonymous" key packet), and // is not included in the signature's intended recipient list. encHandle, _ := pgp.Encryption(). Recipient(bobKeyPub). HiddenRecipient(carolKeyPub). SigningKey(aliceKeyPriv). New() pgpMessage, _ := encHandle.Encrypt([]byte("my message")) // Decrypt checks if bobs key fingerprint is in the intended recipient list // of alice's signature in the message. decHandleBob, _ := pgp.Decryption(). DecryptionKey(bobKeyPriv). VerificationKey(aliceKeyPub). New() decryptedBob, _ := decHandleBob.Decrypt(pgpMessage.Bytes(), crypto.Bytes) fmt.Println(string(decryptedBob.Bytes())) // Disable intended recipient check, there is no info about carols key in the message. // The decryption function tries all supplied keys for decrypting the "anonymous" key packet. // If the check is not disabled, the decryption result would contain a signature error. decHandleCarol, _ := pgp.Decryption(). DecryptionKey(carolKeyPriv). VerificationKey(aliceKeyPub). DisableIntendedRecipients(). New() decryptedCarol, _ := decHandleCarol.Decrypt(pgpMessage.Bytes(), crypto.Bytes) ``` Encrypt and decrypt large messages with the streaming API: ```go pgp := crypto.PGP() // ... See key generation above // Encrypt plain text stream and write the output to a file encHandle, err := pgp.Encryption(). Recipient(bobKeyPub). SigningKey(aliceKeyPriv). New() messageReader, err := os.Open("msg.txt") ciphertextWriter, err := os.Create("out.pgp") ptWriter, err := encHandle.EncryptingWriter(ciphertextWriter, crypto.Armor) _, err = io.Copy(ptWriter, messageReader) err = ptWriter.Close() err = messageReader.Close() err = ciphertextWriter.Close() ctFileRead, err := os.Open("out.pgp") defer ctFileRead.Close() // Decrypt stream and read the result to memory decHandle, err := pgp.Decryption(). DecryptionKey(bobKeyPriv). VerificationKey(aliceKeyPub). New() ptReader, err := decHandle.DecryptingReader(ctFileRead, crypto.Armor) decResult, err := ptReader.ReadAllAndVerifySignature() if sigErr := decResult.SignatureError(); sigErr != nil { // Handle sigErr } // Access decrypted message with decResult.Bytes() ``` ### Generate key Keys are generated with the `GenerateKey` function on the pgp handle. ```go import "github.com/ProtonMail/gopenpgp/v3/constants" const ( name = "Max Mustermann" email = "max.mustermann@example.com" passphrase = []byte("LongSecret") ) pgpDefault := crypto.PGPWithProfile(profile.Default()) pgp4880 := crypto.PGPWithProfile(profile.RFC4880()) pgpCryptoRefresh := crypto.PGPWithProfile(profile.RFC9580()) // Note that RSA keys should not be generated anymore according to // RFC9580. keyGenHandle := pgp4880.KeyGeneration().AddUserId(name, email).New() // Generates rsa keys with 3072 bits rsaKey, err := keyGenHandle.GenerateKey() // Generates rsa keys with 4092 bits rsaKeyHigh, err := keyGenHandle.GenerateKeyWithSecurity(constants.HighSecurity) keyGenHandle = pgpDefault.KeyGeneration().AddUserId(name, email).New() // Generates curve25519 v4 keys. ecKey, err := keyGenHandle.GenerateKey() keyGenHandle = pgpCryptoRefresh.KeyGeneration().AddUserId(name, email).New() // Generates curve25519 v6 keys with RFC9580. ecKey, err = keyGenHandle.GenerateKey() // Generates curve448 v6 keys with RFC9580. ecKeyHigh, err = keyGenHandle.GenerateKeyWithSecurity(constants.HighSecurity) ``` Encrypt (lock) and decrypt (unlock) a secret key: ```go password := []byte("password") pgp := crypto.PGP() // Encrypt key with password lockedKey, err := pgp.LockKey(aliceKeyPriv, password) // Decrypt key with password unlockedKey, err := lockedKey.Unlock(password) ``` ### Detached and inline signatures Sign a plaintext with a private key and verify it with its public key using detached signatures: ```go pgp := crypto.PGP() // ... See generating keys signingMessage := []byte("message to sign") signer, err := pgp.Sign().SigningKey(aliceKeyPriv).Detached().New() signature, err := signer.Sign(signingMessage, crypto.Armor) verifier, err := pgp.Verify().VerificationKey(aliceKeyPub).New() verifyResult, err := verifier.VerifyDetached(signingMessage, signature, crypto.Armor) if sigErr := verifyResult.SignatureError(); sigErr != nil { // Handle sigErr } signer.ClearPrivateParams() ``` Sign a plaintext with a private key and verify it with its public key using inline signatures: ```go pgp := crypto.PGP() // ... See generating keys signingMessage := []byte("message to sign") signer, err := pgp.Sign().SigningKey(aliceKeyPriv).New() signatureMessage, err := signer.Sign(signingMessage, crypto.Armor) verifier, err := pgp.Verify().VerificationKey(aliceKeyPub).New() verifyResult, err := verifier.VerifyInline(signatureMessage, crypto.Armor) if sigErr := verifyResult.SignatureError(); sigErr != nil { // Handle sigErr } // Access signed data with verifyResult.Bytes() signer.ClearPrivateParams() ``` ### Cleartext signed messages ```go pgp := crypto.PGP() // ... See generating keys signingMessage := []byte("message to sign") signer, err := pgp.Sign().SigningKey(aliceKeyPriv).New() cleartextArmored, err := signer.SignCleartext(signingMessage) // CleartextArmored has the form: // -----BEGIN PGP SIGNED MESSAGE----- // ... // -----BEGIN PGP SIGNATURE----- // ... // -----END PGP SIGNATURE----- verifier, err := pgp.Verify().VerificationKey(aliceKeyPub).New() verifyResult, err := verifier.VerifyCleartext(cleartextArmored) if sigErr := verifyResult.SignatureError(); sigErr != nil { // Handle sigErr } signer.ClearPrivateParams() ``` ### Encrypt with different outputs Split encrypted message into key packets and data packets ```go // Non-streaming pgpMessage, err := encHandle.Encrypt(...) keyPackets := pgpMessage.BinaryKeyPacket() dataPackets := pgpMessage.BinaryDataPacket() // Streaming var keyPackets bytes.Buffer var dataPackets bytes.Buffer splitWriter := crypto.NewPGPSplitWriterKeyAndData(&keyPackets, &dataPackets) ptWriter, _ := encHandle.EncryptingWriter(splitWriter, crypto.Bytes) // ... // Key packets are written to keyPackets while data packets are written to dataPackets ``` Produce encrypted detached signatures instead of embedded signatures: ```go // Non-streaming encHandle, err := pgp.Encryption(). Recipient(bobKeyPub). SigningKey(aliceKeyPriv). DetachedSignature(). New() // Enable the detached signature option pgpMessage, err := encHandle.Encrypt(...) pgpMessageEncSig, err := pgpMessage.EncryptedDetachedSignature() // pgpMessage.Bytes() encrypted message without an embedded signature // pgpMessageEncSig.Bytes() encrypted signature message // pgpMessage: key packets|enc data packets // pgpMessageEncSig: key packets|enc signature packet // Streaming // ... var encSigDataPackets bytes.Buffer splitWriter := crypto.NewPGPSplitWriter(&keyPackets, &dataPackets, &encSigDataPackets) ptWriter, err := encHandle.EncryptingWriter(splitWriter, crypto.Bytes) // ... // Key packets are written to keyPackets, data packets are written to dataPackets ,and // Data packets of the encrypted signature to encSigDataPackets ``` ## Using with Go Mobile This library can be compiled with [Gomobile](https://github.com/golang/go/wiki/Mobile) too. First ensure you have a working installation of gomobile: ```bash gomobile version ``` In case this fails, install it with: ```bash go get -u golang.org/x/mobile/cmd/gomobile ``` Then ensure your path env var has gomobile's binary, and it is properly init-ed: ```bash export PATH="$PATH:$GOPATH/bin" gomobile init ``` Then you must ensure that the Android or iOS frameworks are installed and the respective env vars set. Finally, build the application ```bash sh build.sh ``` This script will build for both android and iOS at the same time, to filter one out you can comment out the line in the corresponding section. golang-github-protonmail-gopenpgp-v3-3.1.0/armor/000077500000000000000000000000001472137411600217155ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-v3-3.1.0/armor/armor.go000066400000000000000000000155321472137411600233720ustar00rootroot00000000000000// Package armor contains a set of helper methods for armoring and unarmoring // data. package armor import ( "bytes" "io" "github.com/ProtonMail/go-crypto/openpgp/armor" "github.com/ProtonMail/gopenpgp/v3/constants" "github.com/ProtonMail/gopenpgp/v3/internal" "github.com/pkg/errors" ) // ArmorKey armors input as a public key. func ArmorKey(input []byte) (string, error) { return ArmorWithType(input, constants.PublicKeyHeader) } // ArmorWriterWithType returns a io.WriteCloser which, when written to, writes // armored data to w with the given armorType. func ArmorWriterWithType(w io.Writer, armorType string) (io.WriteCloser, error) { return armor.EncodeWithChecksumOption(w, armorType, internal.ArmorHeaders, constants.ArmorChecksumEnabled) } // ArmorWriterWithTypeChecksum returns a io.WriteCloser which, when written to, writes // armored data to w with the given armorType. // The checksum determines if an armor checksum is written at the end. func ArmorWriterWithTypeChecksum(w io.Writer, armorType string, checksum bool) (io.WriteCloser, error) { return armor.EncodeWithChecksumOption(w, armorType, internal.ArmorHeaders, checksum) } // ArmorWriterWithTypeAndCustomHeaders returns a io.WriteCloser, // which armors input with the given armorType and headers. func ArmorWriterWithTypeAndCustomHeaders(w io.Writer, armorType, version, comment string) (io.WriteCloser, error) { headers := make(map[string]string) if version != "" { headers["Version"] = version } if comment != "" { headers["Comment"] = comment } return armor.EncodeWithChecksumOption(w, armorType, headers, constants.ArmorChecksumEnabled) } // ArmorWithType armors input with the given armorType. func ArmorWithType(input []byte, armorType string) (string, error) { return ArmorWithTypeChecksum(input, armorType, constants.ArmorChecksumEnabled) } // ArmorWithTypeChecksum armors input with the given armorType. // The checksum option determines if an armor checksum is written at the end. func ArmorWithTypeChecksum(input []byte, armorType string, checksum bool) (string, error) { buffer, err := armorWithTypeAndHeaders(input, armorType, internal.ArmorHeaders, checksum) if err != nil { return "", err } return buffer.String(), err } // ArmorWithTypeBytes armors input with the given armorType. func ArmorWithTypeBytes(input []byte, armorType string) ([]byte, error) { return ArmorWithTypeBytesChecksum(input, armorType, constants.ArmorChecksumEnabled) } // ArmorWithTypeBytesChecksum armors input with the given armorType and checksum option. func ArmorWithTypeBytesChecksum(input []byte, armorType string, checksum bool) ([]byte, error) { buffer, err := armorWithTypeAndHeaders(input, armorType, internal.ArmorHeaders, checksum) if err != nil { return nil, err } return buffer.Bytes(), err } // ArmorWithTypeAndCustomHeaders armors input with the given armorType and // headers. func ArmorWithTypeAndCustomHeaders(input []byte, armorType, version, comment string) (string, error) { return ArmorWithTypeAndCustomHeadersChecksum(input, armorType, version, comment, constants.ArmorChecksumEnabled) } // ArmorWithTypeAndCustomHeadersChecksum armors input with the given armorType and // headers and checksum option. func ArmorWithTypeAndCustomHeadersChecksum(input []byte, armorType, version, comment string, checksum bool) (string, error) { headers := make(map[string]string) if version != "" { headers["Version"] = version } if comment != "" { headers["Comment"] = comment } buffer, err := armorWithTypeAndHeaders(input, armorType, headers, checksum) if err != nil { return "", err } return buffer.String(), err } // ArmorWithTypeAndCustomHeadersBytes armors input with the given armorType and // headers. func ArmorWithTypeAndCustomHeadersBytes(input []byte, armorType, version, comment string) ([]byte, error) { headers := make(map[string]string) if version != "" { headers["Version"] = version } if comment != "" { headers["Comment"] = comment } buffer, err := armorWithTypeAndHeaders(input, armorType, headers, constants.ArmorChecksumEnabled) if err != nil { return nil, err } return buffer.Bytes(), err } // ArmorReader returns a io.Reader which, when read, reads // unarmored data from in. func ArmorReader(in io.Reader) (io.Reader, error) { block, err := armor.Decode(in) if err != nil { return nil, err } return block.Body, nil } // Unarmor unarmors an armored input into a byte array. func Unarmor(input string) ([]byte, error) { b, err := internal.Unarmor(input) if err != nil { return nil, errors.Wrap(err, "armor: unable to unarmor") } return io.ReadAll(b.Body) } // UnarmorBytes unarmors an armored input into a byte array. func UnarmorBytes(input []byte) ([]byte, error) { b, err := internal.UnarmorBytes(input) if err != nil { return nil, errors.Wrap(err, "armor: unable to unarmor") } return io.ReadAll(b.Body) } func ArmorPGPSignatureBinary(signature []byte) ([]byte, error) { return ArmorWithTypeBytes(signature, constants.PGPSignatureHeader) } func ArmorPGPSignature(signature []byte) (string, error) { return ArmorWithType(signature, constants.PGPSignatureHeader) } func ArmorPGPMessageBytes(signature []byte) ([]byte, error) { return ArmorWithTypeBytes(signature, constants.PGPMessageHeader) } func ArmorPGPMessage(signature []byte) (string, error) { return ArmorWithType(signature, constants.PGPMessageHeader) } func ArmorPGPMessageBytesChecksum(signature []byte, checksum bool) ([]byte, error) { return ArmorWithTypeBytesChecksum(signature, constants.PGPMessageHeader, checksum) } func ArmorPGPMessageChecksum(signature []byte, checksum bool) (string, error) { return ArmorWithTypeChecksum(signature, constants.PGPMessageHeader, checksum) } const armorPrefix = "-----BEGIN PGP" const maxGarbageBytes = 128 // IsPGPArmored reads a prefix from the reader and checks // if it is equal to a pgp armored message prefix. // Returns an io.Reader that is reset to the state of the in reader, // and a bool that indicates if there is a match. // If reading from the reader fails, the returned bool is set to false. func IsPGPArmored(in io.Reader) (io.Reader, bool) { buffer := make([]byte, len(armorPrefix)+maxGarbageBytes) n, _ := io.ReadFull(in, buffer) outReader := io.MultiReader(bytes.NewReader(buffer[:n]), in) if bytes.Contains(buffer[:n], []byte(armorPrefix)) { return outReader, true } return outReader, false } func armorWithTypeAndHeaders(input []byte, armorType string, headers map[string]string, writeChecksum bool) (*bytes.Buffer, error) { var b bytes.Buffer w, err := armor.EncodeWithChecksumOption(&b, armorType, headers, writeChecksum) if err != nil { return nil, errors.Wrap(err, "armor: unable to encode armoring") } if _, err = w.Write(input); err != nil { return nil, errors.Wrap(err, "armor: unable to write armored to buffer") } if err := w.Close(); err != nil { return nil, errors.Wrap(err, "armor: unable to close armor buffer") } return &b, nil } golang-github-protonmail-gopenpgp-v3-3.1.0/build.sh000077500000000000000000000057371472137411600222470ustar00rootroot00000000000000#!/bin/bash USER_INPUT=$1 NB_INPUTS=$# set -ue pipefail # End the script if any command, or intermediate command, # returns an error code. trap failed_build EXIT # Colors for terminal display red="\e[0;31m" green="\e[0;32m" reset="\033[0m" # Trap in case something went wrong failed_build() { printf "${red}The build failed!\nRun 'make clean' before retrying...\n${reset}" } install_modules() { printf "${green}Start installing go modules and their dependencies ${reset}\n\n" GO111MODULE=on go mod download printf "${green}Done ${reset}\n\n" } install_gomobile() { printf "${green}Installing gomobile fork${reset}\n\n" go get golang.org/x/mobile/cmd/gomobile@latest go get golang.org/x/mobile/cmd/gobind@latest go build golang.org/x/mobile/cmd/gomobile go build golang.org/x/mobile/cmd/gobind PATH=$(pwd):$PATH printf "${green}Done ${reset}\n\n" } get_modules(){ printf "${green}Start installing go modules and their dependencies ${reset}\n\n" GO111MODULE=on go mod download printf "${green}Done ${reset}\n\n" } remove_dir() { DIR=$1 if [ -d "$DIR" ]; then printf "removing old $DIR\n" rm -rf $DIR fi } build() { TARGET=$1 OUTPUT_DIR=$2 TAGS="mobile" if [ $TARGET = "android" ]; then JAVAPKG_FLAG="-javapkg=com.proton.gopenpgp" OUT_EXTENSION="aar" else JAVAPKG_FLAG="" OUT_EXTENSION="xcframework" TAGS="$TAGS,ios" fi TARGET_DIR=${OUT_DIR}/${OUTPUT_DIR} TARGET_OUT_FILE=${TARGET_DIR}/${BUILD_NAME}.${OUT_EXTENSION} mkdir -p $TARGET_DIR printf "${green}Start Building ${TARGET} .. Location: ${TARGET_DIR} ${reset}\n\n" remove_dir $TARGET_OUT_FILE ./gomobile bind -tags $TAGS -target $TARGET $JAVAPKG_FLAG -x -ldflags="-s -w " -o ${TARGET_OUT_FILE} ${PACKAGES} } # import function, add internal package in the build import() { PACKAGES="${PACKAGES} $1" } ## ======== Config =============== # ==== Generic parameters ====== # output directory OUT_DIR="dist" # name of the build output BUILD_NAME="gopenpgp" # ==== Packages to included ===== PACKAGES="" ## crypto must be the first one, and the framework name better same with the first package name import github.com/ProtonMail/gopenpgp/v3/crypto import github.com/ProtonMail/gopenpgp/v3/armor import github.com/ProtonMail/gopenpgp/v3/constants import github.com/ProtonMail/gopenpgp/v3/mime import github.com/ProtonMail/gopenpgp/v3/mobile import github.com/ProtonMail/gopenpgp/v3/profile ######## ======== Main =========== install_modules install_gomobile get_modules go env echo "PATH=$PATH" echo "gomobile:$(which gomobile)" printf "Packages included : ${PACKAGES}\n" ## start building # ================= Apple Builds ====================== # we build the framework for the ios devices and simulator if [ $NB_INPUTS -ne 1 ] || [ $USER_INPUT = apple ]; then build ios,iossimulator,macos apple fi # ================ Android Build ===================== if [ $NB_INPUTS -ne 1 ] || [ $USER_INPUT = android ]; then build android android fi printf "${green}All Done. ${reset}\n\n" trap - EXITgolang-github-protonmail-gopenpgp-v3-3.1.0/constants/000077500000000000000000000000001472137411600226115ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-v3-3.1.0/constants/armor.go000066400000000000000000000013351472137411600242620ustar00rootroot00000000000000// Package constants provides a set of common OpenPGP constants. package constants // Constants for armored data. const ( // ArmorChecksumEnabled defines the default behavior for adding an armor checksum // to an armored message. // // If set to true, an armor checksum is added to the message. // // If set to false, no armor checksum is added. ArmorChecksumEnabled = true ArmorHeaderEnabled = false // can be enabled for debugging at compile time only ArmorHeaderVersion = "GopenPGP " + Version ArmorHeaderComment = "https://gopenpgp.org" PGPMessageHeader = "PGP MESSAGE" PGPSignatureHeader = "PGP SIGNATURE" PublicKeyHeader = "PGP PUBLIC KEY BLOCK" PrivateKeyHeader = "PGP PRIVATE KEY BLOCK" ) golang-github-protonmail-gopenpgp-v3-3.1.0/constants/cipher.go000066400000000000000000000015561472137411600244210ustar00rootroot00000000000000package constants // Cipher suite names. const ( ThreeDES = "3des" TripleDES = "tripledes" // Both "3des" and "tripledes" refer to 3DES. CAST5 = "cast5" AES128 = "aes128" AES192 = "aes192" AES256 = "aes256" ) const ( SIGNATURE_OK int = 0 SIGNATURE_NOT_SIGNED int = 1 SIGNATURE_NO_VERIFIER int = 2 SIGNATURE_FAILED int = 3 SIGNATURE_BAD_CONTEXT int = 4 ) // SecurityLevel constants. // The type is int8 for compatibility with gomobile. const ( // StandardSecurity is the default security level. StandardSecurity int8 = 0 // HighSecurity is the high security level. HighSecurity int8 = 1 ) // Wraps the packet.CipherFunction enum from go-crypto // for go-mobile clients. // int8 type for go-mobile support. const ( Cipher3DES int8 = 2 CipherCAST5 int8 = 3 CipherAES128 int8 = 7 CipherAES192 int8 = 8 CipherAES256 int8 = 9 ) golang-github-protonmail-gopenpgp-v3-3.1.0/constants/compression.go000066400000000000000000000004121472137411600254760ustar00rootroot00000000000000package constants const ( // Use no compression (default). NoCompression int8 = 0 // Use compression defined by the pgp profile. DefaultCompression int8 = 1 // Use ZIP compression. ZIPCompression int8 = 2 // Use ZLIB compression. ZLIBCompression int8 = 3 ) golang-github-protonmail-gopenpgp-v3-3.1.0/constants/context.go000066400000000000000000000001041472137411600246170ustar00rootroot00000000000000package constants const SignatureContextName = "context@proton.ch" golang-github-protonmail-gopenpgp-v3-3.1.0/constants/signature.go000066400000000000000000000011551472137411600251430ustar00rootroot00000000000000package constants // OpenPGP signature types. // int8 type for go-mobile clients. const ( SigTypeBinary int8 = 0x00 SigTypeText int8 = 0x01 SigTypeGenericCert int8 = 0x10 SigTypePersonaCert int8 = 0x11 SigTypeCasualCert int8 = 0x12 SigTypePositiveCert int8 = 0x13 SigTypeSubkeyBinding int8 = 0x18 SigTypePrimaryKeyBinding int8 = 0x19 SigTypeDirectSignature int8 = 0x1F SigTypeKeyRevocation int8 = 0x20 SigTypeSubkeyRevocation int8 = 0x28 SigTypeCertificationRevocation int8 = 0x30 ) golang-github-protonmail-gopenpgp-v3-3.1.0/constants/version.go000066400000000000000000000000531472137411600246230ustar00rootroot00000000000000package constants const Version = "3.1.0" golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/000077500000000000000000000000001472137411600221155ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/base_test.go000066400000000000000000000037731472137411600244270ustar00rootroot00000000000000package crypto import ( "crypto/rsa" "math/big" "os" "strings" "testing" "github.com/ProtonMail/go-crypto/openpgp/ecdh" "github.com/ProtonMail/go-crypto/openpgp/eddsa" "github.com/ProtonMail/gopenpgp/v3/profile" "github.com/stretchr/testify/assert" ) const testTime = 1557754627 // 2019-05-13T13:37:07+00:00 const testMessage = "Hello world!" var testPGP *PGPHandle var testProfiles []*profile.Custom var testProfileNames []string func readTestFile(name string, trimNewlines bool) string { data, err := os.ReadFile("testdata/" + name) //nolint if err != nil { panic(err) } if trimNewlines { return strings.TrimRight(string(data), "\n") } return string(data) } func init() { testPGP = PGP() testPGP.defaultTime = NewConstantClock(testTime) // 2019-05-13T13:37:07+00:00 testProfiles = []*profile.Custom{profile.Default(), profile.RFC4880(), profile.RFC9580()} testProfileNames = []string{"Default", "RFC4880", "RFC9580"} initEncDecTest() initGenerateKeys() initArmoredKeys() initKeyRings() } func assertBigIntCleared(t *testing.T, x *big.Int) { w := x.Bits() for k := range w { assert.Exactly(t, big.Word(0x00), w[k]) } } func assertMemCleared(t *testing.T, b []byte) { for k := range b { assert.Exactly(t, uint8(0x00), b[k]) } } func assertRSACleared(t *testing.T, rsaPriv *rsa.PrivateKey) { assertBigIntCleared(t, rsaPriv.D) for idx := range rsaPriv.Primes { assertBigIntCleared(t, rsaPriv.Primes[idx]) } assertBigIntCleared(t, rsaPriv.Precomputed.Qinv) assertBigIntCleared(t, rsaPriv.Precomputed.Dp) assertBigIntCleared(t, rsaPriv.Precomputed.Dq) for idx := range rsaPriv.Precomputed.CRTValues { assertBigIntCleared(t, rsaPriv.Precomputed.CRTValues[idx].Exp) assertBigIntCleared(t, rsaPriv.Precomputed.CRTValues[idx].Coeff) assertBigIntCleared(t, rsaPriv.Precomputed.CRTValues[idx].R) } } func assertEdDSACleared(t *testing.T, priv *eddsa.PrivateKey) { assertMemCleared(t, priv.D) } func assertECDHCleared(t *testing.T, priv *ecdh.PrivateKey) { assertMemCleared(t, priv.D) } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/crypto.go000066400000000000000000000047311472137411600237710ustar00rootroot00000000000000// Package crypto provides a high-level API for common OpenPGP functionality. // The package provides abstract interfaces for encryption ([PGPEncryption]), // decryption ([PGPDecryption]), signing ([PGPSign]), and verifying ([PGPVerify]). // // # Usage // // To get a concrete instantiation of the interfaces use the top level [PGPHandle] by // calling PGP() or PGPWithProfile(...). An example to instantiate a handle // that implements [PGPEncryption]: // // pgp := PGP() // encryptionHandle, _ :=pgp.Encryption().Password(...).New() package crypto import ( "time" "github.com/ProtonMail/gopenpgp/v3/profile" ) type PGPHandle struct { profile *profile.Custom defaultTime Clock } // PGP creates a PGPHandle to interact with the API. // Uses the default profile for configuration. func PGP() *PGPHandle { return PGPWithProfile(profile.Default()) } // PGPWithProfile creates a PGPHandle to interact with the API. // Uses the provided profile for configuration. func PGPWithProfile(profile *profile.Custom) *PGPHandle { return &PGPHandle{ profile: profile, defaultTime: time.Now, } } // Encryption returns a builder to create an EncryptionHandle // for encrypting messages. func (p *PGPHandle) Encryption() *EncryptionHandleBuilder { return newEncryptionHandleBuilder(p.profile, p.defaultTime) } // Decryption returns a builder to create a DecryptionHandle // for decrypting pgp messages. func (p *PGPHandle) Decryption() *DecryptionHandleBuilder { return newDecryptionHandleBuilder(p.profile, p.defaultTime) } // Sign returns a builder to create a SignHandle // for signing messages. func (p *PGPHandle) Sign() *SignHandleBuilder { return newSignHandleBuilder(p.profile, p.defaultTime) } // Verify returns a builder to create an VerifyHandle // for verifying signatures. func (p *PGPHandle) Verify() *VerifyHandleBuilder { return newVerifyHandleBuilder(p.profile, p.defaultTime) } // KeyGeneration returns a builder to create a KeyGeneration handle. func (p *PGPHandle) KeyGeneration() *KeyGenerationBuilder { return newKeyGenerationBuilder(p.profile, p.defaultTime) } // LockKey encrypts the private parts of a copy of the input key with the given passphrase. func (p *PGPHandle) LockKey(key *Key, passphrase []byte) (*Key, error) { return key.lock(passphrase, p.profile) } // GenerateSessionKey generates a random session key for the profile. func (p *PGPHandle) GenerateSessionKey() (*SessionKey, error) { config := p.profile.EncryptionConfig() return generateSessionKey(config) } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/crypto_example_test.go000066400000000000000000000472151472137411600265470ustar00rootroot00000000000000package crypto import ( "bytes" "encoding/hex" "fmt" "io" "strings" "github.com/ProtonMail/gopenpgp/v3/constants" "github.com/ProtonMail/gopenpgp/v3/profile" ) const examplePubKey = `-----BEGIN PGP PUBLIC KEY BLOCK----- xiYEZIbSkxsHknQrXGfb+kM2iOsOvin8yE05ff5hF8KE6k+saspAZc0VdXNlciA8 dXNlckB0ZXN0LnRlc3Q+wocEExsIAD0FAmSG0pMJkEHsytogdrSJFiEEamc2vcEG XMMaYxmDQezK2iB2tIkCGwMCHgECGQECCwcCFQgCFgADJwcCAABTnme46ymbAs0X 7tX3xWu+9O+LLdM0aAUyV6FwUNWcy47IfmTunwdqHZ2CbUGLLb+OR/9yci1aIHDJ xXmJh3kj9wDOJgRkhtKTGX6Xe04jkL+7ikivpOB0/ZSq+fnZr2+76Mf/InbOrpxJ wnQEGBsIACoFAmSG0pMJkEHsytogdrSJFiEEamc2vcEGXMMaYxmDQezK2iB2tIkC GwwAAMJizYj3AFqQi70eHGzhHcmr0XwnsAfLGw0vQaiZn6HGITQw5nBGvXQPF9Vp FpsXV9x/08dIdfZLAQVdQowgeBsxCw== =JIkN -----END PGP PUBLIC KEY BLOCK-----` const examplePrivKey = `-----BEGIN PGP PRIVATE KEY BLOCK----- xUkEZIbSkxsHknQrXGfb+kM2iOsOvin8yE05ff5hF8KE6k+saspAZQCy/kfFUYc2 GkpOHc42BI+MsysKzk4ofjBAfqM+bb7goQ3hzRV1c2VyIDx1c2VyQHRlc3QudGVz dD7ChwQTGwgAPQUCZIbSkwmQQezK2iB2tIkWIQRqZza9wQZcwxpjGYNB7MraIHa0 iQIbAwIeAQIZAQILBwIVCAIWAAMnBwIAAFOeZ7jrKZsCzRfu1ffFa77074st0zRo BTJXoXBQ1ZzLjsh+ZO6fB2odnYJtQYstv45H/3JyLVogcMnFeYmHeSP3AMdJBGSG 0pMZfpd7TiOQv7uKSK+k4HT9lKr5+dmvb7vox/8ids6unEkAF1v8fCKogIrtBWVT nVbwnovjM3LLexpXFZSgTKRcNMgPRMJ0BBgbCAAqBQJkhtKTCZBB7MraIHa0iRYh BGpnNr3BBlzDGmMZg0HsytogdrSJAhsMAADCYs2I9wBakIu9Hhxs4R3Jq9F8J7AH yxsNL0GomZ+hxiE0MOZwRr10DxfVaRabF1fcf9PHSHX2SwEFXUKMIHgbMQs= =bJqd -----END PGP PRIVATE KEY BLOCK-----` const exampleEncryptedMessagePw = `-----BEGIN PGP MESSAGE----- wy4ECQMIP4yfOrrWtD/g8JituG2N1xeV1o6Frdc3yn7JRoUMv0E69MyI/ito/OH2 0jsBi1NQPKaykn/nSxv+6xzAEWw2lZ6g6hy/gAGgbYy64Fkh652WMvjO9KKDZycB orleBckXgArj64+2Kw== -----END PGP MESSAGE-----` const exampleEncryptedMessagePub = `-----BEGIN PGP MESSAGE----- wUQDYc6clYlCdtoZPfr2cdbY5lVXC+J7/4CpjCocMlEqs739c5cu6rwx8yUZByKm a/HB5JEf9oIsN/ekyHTmcftfTetwiNI7AfuPTGQYB3/PtamMToIClX5Ca+eDb6iU VS0r4gpTv5iIvl9+k4sbSvxwjNMLBy9DyB+mlFc3OZ5dtFk= -----END PGP MESSAGE-----` const exampleEncryptedAndSigned = `-----BEGIN PGP MESSAGE----- wUQDYc6clYlCdtoZgMQH5tynaMh60pY+uo3KuXzCM+bDkO1VqrL5IBRQWWMZB/2r H8be1jZayJ8a1F+FG6Xs+LO2INR4lNLAFAHoLWu2En755DDZJwQwnDQ6Gywq26aq STVC0Bt+srqxxOKJJFA2lN4tlVsn1pKsgaqO6s52JDFlT0OijF8wgz/kfc/ZwT7Z EBdqURMaF3wUlQ5nX2/ZDQJNfU/d79W0+8IQ7QrVhVQuV7sub7EbpqSuFTwqPt73 jsLFlYxlYsgaKCHsmVVJWb1uIdPzHXXajTVPa1aRkkyCYMayXJEWOu7+HoW0Ipk1 piIFyQpQFvj9RAwuKaGQUfb5KRP1fegjwZd0/8TWDfLPuD2Fc3LBicxpI1Hk -----END PGP MESSAGE-----` const exampleDetachedSignature = `-----BEGIN PGP SIGNATURE----- wnEEABsIACcFAmSe4bEJkEHsytogdrSJFiEEamc2vcEGXMMaYxmDQezK2iB2tIkA AIL40zuQXGBliZqje7eniv34NFZf2zQIE8gQOdcnWqFLlgg210RHjqqS2qGOuQyL exN6Dbkaubvk6EhvTmYXIXnSAQ== =EeGr -----END PGP SIGNATURE-----` const exampleInlineSignature = `-----BEGIN PGP MESSAGE----- xA0DAAgbQezK2iB2tIkByxViAAAAAABtZXNzYWdlIHRvIHNpZ27CcQQAGwgAJwUC ZJ7jVQmQQezK2iB2tIkWIQRqZza9wQZcwxpjGYNB7MraIHa0iQAA/+K//wXxUyVf m50qAP92QZTqsHIokut9xP8Lp/ntSdKWBLdmoWHVpXElGpnIinSNt6NNjHj+S22u QqO+M5PHk0cI -----END PGP MESSAGE-----` const exampleCleartextSignature = `-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA512 message to sign -----BEGIN PGP SIGNATURE----- wnEEARsKACcFAmSe5K0JkEHsytogdrSJFiEEamc2vcEGXMMaYxmDQezK2iB2tIkA APwuHaxUQ7xX4WdqWm7WnipmbM/ARTJPESACNoFlw7p/aHuXw+nyolUeIRnadyle 0KepPKwDaTY+7Jk7/5kv7NiqAg== -----END PGP SIGNATURE-----` const exampleSplitMessage = `c1440361ce9c95894276da19cf0760b3a1150038c6d9ab20a5594fc9e32ce12009fb0a3ec12783b8efcf57521907d012786468567d736db82a9b160a598ea8decd762b982063 d2c0140104f3439588864ca36d6c15c0ae9364c706a869f13fc71987acd5061716914b03b4ef1884d67d19f28e9c29447fbd76781cd9b69bad22fc2b7eefd0d1b6c4e5d3f90368d19b5a2eb02cb1fb4d706f77feb1b200ac553cd872e1e695bafbac39fbf729f89a96aaf9fdef72c801545db2e627b357df18d05841f2fbd5aeb82b38db28a7f4cd946b17f98922fcbd78cf03b3ff7247918f381e61482960a9eec2192c64aa1a3eddbab486a7372c65e8f2c9b284f6b232cd3a4147fa374635cd1ad7e8b210334fce25c49cce99f91ff835dbfb3c6a27` const exampleEncryptedDetachedMessage = `-----BEGIN PGP MESSAGE----- wVQDYc6clYlCdtoZVaZe8pDekqVSnY9/wtXIPV92Yi1b/Nc0cxaw3CyG7xkpCbnc V5NWsbpp0NaJ3Gxq/APdetC3iPG+AjM4xuWKhZWZ3/+bea/2q8jSOwF43weMcuQF zXxGfqB9uLYsOXejBTO4oPDbuWH11SVibxa6k1X79l2+kf2dDgruhMk564h4SU6v dbID -----END PGP MESSAGE-----` const exampleEncryptedDetachedSignatureMessage = `-----BEGIN PGP MESSAGE----- wVQDYc6clYlCdtoZVaZe8pDekqVSnY9/wtXIPV92Yi1b/Nc0cxaw3CyG7xkpCbnc V5NWsbpp0NaJ3Gxq/APdetC3iPG+AjM4xuWKhZWZ3/+bea/2q8jSpAHHbawcWmFq ecrYdNNCv7KZS3ofScFXVuYWI8tc8sgaCUd2b82krn0dWRAzaxBuz+rJ99/jQa8U GZSc+PaljzEvgR+GoQc5h8VJ58UmDXoN9VhWYKBBz1B1bkCu1vsDNS1yXk/XNi2e BMEdvkP9hUOsJTO9e1qQLhmmEQlyHkmQGSyIHFNaYMI18RSUVmfZwZ7fsL/I07zp nNWmL4dHU3Ba+56V -----END PGP MESSAGE-----` func ExamplePGPHandle_Encryption_password() { // Encrypt data with a password password := []byte("hunter2") pgp := PGP() encHandle, err := pgp.Encryption(). Password(password). New() if err != nil { return } pgpMessage, err := encHandle.Encrypt([]byte("my message")) if err != nil { return } armored, err := pgpMessage.Armor() if err != nil { return } fmt.Println(armored) } func ExamplePGPHandle_Encryption_asymmetric() { // Encrypt data with a public key publicKey, err := NewKeyFromArmored(examplePubKey) if err != nil { return } pgp := PGP() encHandle, err := pgp.Encryption(). Recipient(publicKey). New() if err != nil { return } pgpMessage, err := encHandle.Encrypt([]byte("my message")) if err != nil { return } armored, err := pgpMessage.Armor() if err != nil { return } fmt.Println(armored) } func ExamplePGPHandle_Encryption_signcrypt() { // Encrypt data with a public key // and sign with private key publicKey, err := NewKeyFromArmored(examplePubKey) if err != nil { return } privateKey, err := NewKeyFromArmored(examplePrivKey) if err != nil { return } defer privateKey.ClearPrivateParams() pgp := PGP() encHandle, err := pgp.Encryption(). Recipient(publicKey). SigningKey(privateKey). New() if err != nil { return } pgpMessage, err := encHandle.Encrypt([]byte("my message")) if err != nil { return } armored, err := pgpMessage.Armor() if err != nil { return } fmt.Println(armored) } func ExamplePGPHandle_Encryption_stream() { // Encrypt data with a public key // and sign with private key streaming publicKey, err := NewKeyFromArmored(examplePubKey) if err != nil { return } privateKey, err := NewKeyFromArmored(examplePrivKey) if err != nil { return } defer privateKey.ClearPrivateParams() pgp := PGP() encHandle, err := pgp.Encryption(). Recipient(publicKey). SigningKey(privateKey). New() if err != nil { return } messageReader := strings.NewReader("my message") var ciphertextWriter bytes.Buffer ptWriter, err := encHandle.EncryptingWriter(&ciphertextWriter, Armor) if err != nil { fmt.Println(err) return } if _, err = io.Copy(ptWriter, messageReader); err != nil { return } if err = ptWriter.Close(); err != nil { return } fmt.Println(ciphertextWriter.String()) } func ExamplePGPHandle_Encryption_split() { // Split encrypted message into key packets and data packets. publicKey, err := NewKeyFromArmored(examplePubKey) if err != nil { return } privateKey, err := NewKeyFromArmored(examplePrivKey) if err != nil { return } defer privateKey.ClearPrivateParams() pgp := PGP() encHandle, err := pgp.Encryption(). Recipient(publicKey). SigningKey(privateKey). New() if err != nil { return } var keyPackets bytes.Buffer var dataPackets bytes.Buffer splitWriter := NewPGPSplitWriterKeyAndData(&keyPackets, &dataPackets) ptWriter, err := encHandle.EncryptingWriter(splitWriter, Bytes) if err != nil { return } if _, err = io.Copy(ptWriter, strings.NewReader("my message")); err != nil { return } if err = ptWriter.Close(); err != nil { return } fmt.Printf("%x\n", keyPackets.Bytes()) fmt.Printf("%x\n", dataPackets.Bytes()) } func ExamplePGPHandle_Encryption_detached() { // Produce encrypted detached signatures instead of // embedded signatures: publicKey, err := NewKeyFromArmored(examplePubKey) if err != nil { return } privateKey, err := NewKeyFromArmored(examplePrivKey) if err != nil { return } defer privateKey.ClearPrivateParams() pgp := PGP() encHandle, err := pgp.Encryption(). Recipient(publicKey). SigningKey(privateKey). DetachedSignature(). New() if err != nil { return } var pgpMessage bytes.Buffer var pgpSignatureMessage bytes.Buffer splitWriter := NewPGPSplitWriterDetachedSignature(&pgpMessage, &pgpSignatureMessage) ptWriter, err := encHandle.EncryptingWriter(splitWriter, Armor) if err != nil { return } if _, err = io.Copy(ptWriter, strings.NewReader("my message")); err != nil { return } if err = ptWriter.Close(); err != nil { return } fmt.Println(pgpMessage.String()) fmt.Println(pgpSignatureMessage.String()) } func ExamplePGPHandle_Decryption_password() { // Decrypt data with a password pgp := PGP() decHandle, err := pgp. Decryption(). Password([]byte("hunter2")). New() if err != nil { fmt.Println(err) return } decrypted, err := decHandle.Decrypt([]byte(exampleEncryptedMessagePw), Armor) if err != nil { fmt.Println(err) return } fmt.Println(string(decrypted.Bytes())) // Output: my message } func ExamplePGPHandle_Decryption_asymmetric() { // Decrypt armored encrypted message using // the private key and obtain the plaintext privateKey, err := NewKeyFromArmored(examplePrivKey) if err != nil { fmt.Println(err) return } defer privateKey.ClearPrivateParams() pgp := PGP() decHandle, err := pgp. Decryption(). DecryptionKey(privateKey). New() if err != nil { fmt.Println(err) return } decrypted, err := decHandle.Decrypt([]byte(exampleEncryptedMessagePub), Armor) if err != nil { fmt.Println(err) return } fmt.Println(decrypted.String()) // Output: my message } func ExamplePGPHandle_Decryption_signcrypt() { // Decrypt armored encrypted message using // the private key and obtain the plaintext publicKey, err := NewKeyFromArmored(examplePubKey) if err != nil { fmt.Println(err) return } privateKey, err := NewKeyFromArmored(examplePrivKey) if err != nil { fmt.Println(err) return } defer privateKey.ClearPrivateParams() pgp := PGP() decHandle, err := pgp. Decryption(). DecryptionKey(privateKey). VerificationKey(publicKey). New() if err != nil { fmt.Println(err) return } decrypted, err := decHandle.Decrypt([]byte(exampleEncryptedAndSigned), Armor) if err != nil { return } if sigErr := decrypted.SignatureError(); sigErr != nil { fmt.Println(sigErr) return } else { fmt.Println("OK") } fmt.Println(decrypted.String()) // Output: OK // my message } func ExamplePGPHandle_Decryption_split() { // Decrypt key and data packet // separately. data := strings.Split(exampleSplitMessage, "\n") keyPacket, _ := hex.DecodeString(data[0]) dataPacket, _ := hex.DecodeString(data[1]) publicKey, err := NewKeyFromArmored(examplePubKey) if err != nil { fmt.Println(err) return } privateKey, err := NewKeyFromArmored(examplePrivKey) if err != nil { fmt.Println(err) return } defer privateKey.ClearPrivateParams() pgp := PGP() decHandle, err := pgp. Decryption(). DecryptionKey(privateKey). New() if err != nil { fmt.Println(err) return } sessionKey, err := decHandle.DecryptSessionKey(keyPacket) if err != nil { fmt.Println(err) return } decHandle, err = pgp. Decryption(). SessionKey(sessionKey). VerificationKey(publicKey). DisableIntendedRecipients(). New() if err != nil { fmt.Println(err) return } decrypted, err := decHandle.Decrypt(dataPacket, Bytes) if err != nil { fmt.Println(err) return } if sigErr := decrypted.SignatureError(); sigErr != nil { fmt.Println(sigErr) return } else { fmt.Println("OK") } fmt.Println(decrypted.String()) // Output: OK // my message } func ExamplePGPHandle_Decryption_stream() { // Decrypt armored encrypted message using // the private key and obtain the plaintext with streaming publicKey, err := NewKeyFromArmored(examplePubKey) if err != nil { return } privateKey, err := NewKeyFromArmored(examplePrivKey) if err != nil { return } defer privateKey.ClearPrivateParams() pgp := PGP() decHandle, err := pgp. Decryption(). DecryptionKey(privateKey). VerificationKey(publicKey). New() if err != nil { fmt.Println(err) return } ciphertextReader := strings.NewReader(exampleEncryptedAndSigned) ptReader, err := decHandle.DecryptingReader(ciphertextReader, Armor) if err != nil { fmt.Println(err) return } decrypted, err := ptReader.ReadAllAndVerifySignature() if err != nil { fmt.Println(err) return } if sigErr := decrypted.SignatureError(); sigErr != nil { fmt.Println(sigErr) return } else { fmt.Println("OK") } fmt.Println(decrypted.String()) // Output: OK // my message } func ExamplePGPHandle_Decryption_detached() { // Decrypt armored encrypted message and verify an encrypted // detached signature. publicKey, err := NewKeyFromArmored(examplePubKey) if err != nil { return } privateKey, err := NewKeyFromArmored(examplePrivKey) if err != nil { return } defer privateKey.ClearPrivateParams() pgp := PGP() decHandle, err := pgp. Decryption(). DecryptionKey(privateKey). VerificationKey(publicKey). New() if err != nil { fmt.Println(err) return } ciphertextReader := NewPGPSplitReader( strings.NewReader(exampleEncryptedDetachedMessage), strings.NewReader(exampleEncryptedDetachedSignatureMessage), ) ptReader, err := decHandle.DecryptingReader(ciphertextReader, Armor) if err != nil { fmt.Println(err) return } decrypted, err := ptReader.ReadAllAndVerifySignature() if err != nil { fmt.Println(err) return } if sigErr := decrypted.SignatureError(); sigErr != nil { fmt.Println(sigErr) return } else { fmt.Println("OK") } fmt.Println(decrypted.String()) // Output: OK // my message } func ExamplePGPHandle_KeyGeneration_basic() { pgp := PGP() // Generate a PGP key genHandle := pgp.KeyGeneration(). AddUserId("Max Mustermann", "max.mustermann@example.com"). New() key, err := genHandle.GenerateKey() if err != nil { return } fmt.Println(key.Armor()) } func ExamplePGPHandle_KeyGeneration_profile() { // Generate a PGP key with the crypto-refresh profile pgp := PGPWithProfile(profile.RFC9580()) genHandle := pgp.KeyGeneration(). AddUserId("Max Mustermann", "max.mustermann@example.com"). New() key, err := genHandle.GenerateKey() if err != nil { return } fmt.Println(key.Armor()) } func ExamplePGPHandle_KeyGeneration_level() { // Generate a PGP key with the crypto-refresh profile // higher security level (Curve448) pgp := PGPWithProfile(profile.RFC9580()) genHandle := pgp.KeyGeneration(). AddUserId("Max Mustermann", "max.mustermann@example.com"). New() key, err := genHandle.GenerateKeyWithSecurity(constants.HighSecurity) if err != nil { return } fmt.Println(key.Armor()) } func ExamplePGPHandle_Sign_detached() { // Sign a plaintext with a private key // using a detached signatures. privateKey, err := NewKeyFromArmored(examplePrivKey) if err != nil { return } defer privateKey.ClearPrivateParams() pgp := PGP() signingMessage := []byte("message to sign") signer, _ := pgp.Sign(). SigningKey(privateKey). Detached(). New() signature, err := signer.Sign(signingMessage, Armor) if err != nil { return } fmt.Println(string(signature)) } func ExamplePGPHandle_Sign_inline() { // Sign a plaintext with a private key // using a inline signature. privateKey, err := NewKeyFromArmored(examplePrivKey) if err != nil { return } defer privateKey.ClearPrivateParams() pgp := PGP() signingMessage := []byte("message to sign") signer, _ := pgp.Sign(). SigningKey(privateKey). New() signatureMessage, err := signer.Sign(signingMessage, Armor) if err != nil { return } fmt.Println(string(signatureMessage)) } func ExamplePGPHandle_Sign_cleartext() { // Sign a plaintext with a private key // using the cleartext signature framework. privateKey, err := NewKeyFromArmored(examplePrivKey) if err != nil { return } defer privateKey.ClearPrivateParams() pgp := PGP() signingMessage := []byte("message to sign") signer, _ := pgp.Sign(). SigningKey(privateKey). New() signatureMessage, err := signer.SignCleartext(signingMessage) if err != nil { return } fmt.Println(string(signatureMessage)) } func ExamplePGPHandle_Sign_stream() { // Sign a plaintext with a private key // using a inline signature with streaming. privateKey, err := NewKeyFromArmored(examplePrivKey) if err != nil { return } defer privateKey.ClearPrivateParams() pgp := PGP() signer, _ := pgp.Sign(). SigningKey(privateKey). New() var signedMessage bytes.Buffer messageWriter, err := signer.SigningWriter(&signedMessage, Armor) if err != nil { return } if _, err = io.Copy(messageWriter, strings.NewReader("message to sign")); err != nil { return } if err = messageWriter.Close(); err != nil { return } fmt.Println(signedMessage.String()) } func ExamplePGPHandle_Verify_detached() { // Verify detached signature with a public key. verifyMessage := []byte("message to sign") publicKey, err := NewKeyFromArmored(examplePubKey) if err != nil { fmt.Println(err) return } pgp := PGP() verifier, _ := pgp.Verify(). VerificationKey(publicKey). New() verifyResult, err := verifier.VerifyDetached(verifyMessage, []byte(exampleDetachedSignature), Armor) if err != nil { fmt.Println(err) return } if sigErr := verifyResult.SignatureError(); sigErr != nil { fmt.Println(sigErr) } else { fmt.Println("OK") } // Output: OK } func ExamplePGPHandle_Verify_inline() { // Verify a inline signed message with a public key. publicKey, err := NewKeyFromArmored(examplePubKey) if err != nil { fmt.Println(err) return } pgp := PGP() verifier, _ := pgp.Verify(). VerificationKey(publicKey). New() verifyResult, err := verifier.VerifyInline([]byte(exampleInlineSignature), Armor) if err != nil { fmt.Println(err) return } if sigErr := verifyResult.SignatureError(); sigErr != nil { fmt.Println(sigErr) } else { fmt.Println("OK") } fmt.Println(verifyResult.String()) // Output: OK // message to sign } func ExamplePGPHandle_Verify_cleartext() { // Verify a cleartext signed message with a public key. publicKey, err := NewKeyFromArmored(examplePubKey) if err != nil { fmt.Println(err) return } pgp := PGP() verifier, _ := pgp.Verify(). VerificationKey(publicKey). New() verifyResult, err := verifier.VerifyCleartext([]byte(exampleCleartextSignature)) if err != nil { fmt.Println(err) return } if sigErr := verifyResult.SignatureError(); sigErr != nil { fmt.Println(sigErr) } else { fmt.Println("OK") } fmt.Println(string(verifyResult.Cleartext())) // Output: OK // message to sign } func ExamplePGPHandle_Verify_stream() { // Verify a inline signed message with a public key using streaming. publicKey, err := NewKeyFromArmored(examplePubKey) if err != nil { fmt.Println(err) return } pgp := PGP() verifier, _ := pgp.Verify(). VerificationKey(publicKey). New() messageReader, err := verifier.VerifyingReader(nil, strings.NewReader(exampleInlineSignature), Armor) if err != nil { fmt.Println(err) return } verifyResult, err := messageReader.ReadAllAndVerifySignature() if err != nil { fmt.Println(err) return } if sigErr := verifyResult.SignatureError(); sigErr != nil { fmt.Println(sigErr) } else { fmt.Println("OK") } fmt.Println(verifyResult.String()) // Output: OK // message to sign } func ExamplePGPHandle_LockKey() { // Encrypt secret material in a private key with a passphrase. privateKey, err := NewKeyFromArmored(examplePrivKey) if err != nil { fmt.Println(err) return } defer privateKey.ClearPrivateParams() pgp := PGP() lockedKey, err := pgp.LockKey(privateKey, []byte("password")) if err != nil { fmt.Println(err) return } locked, _ := lockedKey.IsLocked() fmt.Println(locked) // Output: true } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/decryption.go000066400000000000000000000047231472137411600246320ustar00rootroot00000000000000package crypto // PGPDecryption is an interface for decrypting pgp messages with GopenPGP. // Use the DecryptionHandleBuilder to create a handle that implements PGPDecryption. type PGPDecryption interface { // DecryptingReader returns a wrapper around underlying encryptedMessage Reader, // such that any read-operation via the wrapper results in a read from the decrypted pgp message. // The returned VerifyDataReader has to be fully read before any potential signatures can be verified. // Either read the message fully end then call VerifySignature or use the helper method ReadAllAndVerifySignature. // The encoding indicates if the input message should be unarmored or not, i.e., Bytes/Armor/Auto // where Auto tries to detect automatically. // If encryptedMessage is of type PGPSplitReader, the method tries to verify an encrypted detached signature // that is read from the separate reader. DecryptingReader(encryptedMessage Reader, encoding int8) (*VerifyDataReader, error) // Decrypt decrypts an encrypted pgp message. // Returns a VerifiedDataResult, which can be queried for potential signature verification errors, // and the plaintext data. Note that on a signature error, the method does not return an error. // Instead, the signature error is stored within the VerifiedDataResult. // The encoding indicates if the input message should be unarmored or not, i.e., Bytes/Armor/Auto // where Auto tries to detect automatically. Decrypt(pgpMessage []byte, encoding int8) (*VerifiedDataResult, error) // DecryptDetached provides the same functionality as Decrypt but allows // to supply an encrypted detached signature that should be decrypted and verified // against the data in the pgp message. If encDetachedSignature is nil, the behavior is similar // to Decrypt. The encoding indicates if the input message should be unarmored or not, // i.e., Bytes/Armor/Auto where Auto tries to detect automatically. DecryptDetached(pgpMessage []byte, encDetachedSignature []byte, encoding int8) (*VerifiedDataResult, error) // DecryptSessionKey decrypts an encrypted session key. // To decrypt a session key, the decryption handle must contain either a decryption key or a password. DecryptSessionKey(keyPackets []byte) (*SessionKey, error) // ClearPrivateParams clears all private key material contained in EncryptionHandle from memory. ClearPrivateParams() } type Reader interface { Read(b []byte) (n int, err error) } type PGPSplitReader interface { Reader Signature() Reader } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/decryption_core.go000066400000000000000000000272171472137411600256450ustar00rootroot00000000000000package crypto import ( "bytes" "io" "github.com/ProtonMail/go-crypto/openpgp/packet" openpgp "github.com/ProtonMail/go-crypto/openpgp/v2" "github.com/ProtonMail/gopenpgp/v3/constants" "github.com/ProtonMail/gopenpgp/v3/internal" "github.com/pkg/errors" ) type pgpSplitReader struct { encMessage, encSignature Reader } // pgpSplitReader implements the PGPSplitReader interface func (mw *pgpSplitReader) Read(b []byte) (int, error) { return mw.encMessage.Read(b) } func (mw *pgpSplitReader) Signature() Reader { return mw.encSignature } func NewPGPSplitReader(pgpMessage Reader, pgpEncryptedSignature Reader) *pgpSplitReader { return &pgpSplitReader{ encMessage: pgpMessage, encSignature: pgpEncryptedSignature, } } // decryptStream decrypts the stream either with the secret keys or a password. func (dh *decryptionHandle) decryptStream(encryptedMessage Reader) (plainMessage *VerifyDataReader, err error) { var entries openpgp.EntityList config := dh.decryptionConfig(dh.clock().Unix()) if dh.DecryptionKeyRing != nil { entries = dh.DecryptionKeyRing.entities } if dh.VerifyKeyRing != nil { entries = append(entries, dh.VerifyKeyRing.entities...) } if dh.VerificationContext != nil { config.KnownNotations = map[string]bool{constants.SignatureContextName: true} } var messageDetails *openpgp.MessageDetails if dh.DecryptionKeyRing != nil { // Private key based decryption messageDetails, err = openpgp.ReadMessage(encryptedMessage, entries, nil, config) if err != nil { return nil, errors.Wrap(err, "gopenpgp: decrypting message with private keys failed") } } else { // Password based decryption var foundPassword = false resetReader := internal.NewResetReader(encryptedMessage) for _, password := range dh.Passwords { prompt := createPasswordPrompt(password) messageDetails, err = openpgp.ReadMessage(resetReader, entries, prompt, config) if err == nil { foundPassword = true resetReader.DisableBuffering() break } if _, err := resetReader.Reset(); err != nil { // Should not happen. return nil, errors.Wrap(err, "gopenpgp: buffer reset failed") } } if !foundPassword { // Parsing errors when reading the message are most likely caused by incorrect password, but we cannot know for sure return nil, errors.New("gopenpgp: error in reading password protected message: wrong password or malformed message") } } // Add utf8 sanitizer if signature has type packet.SigTypeText internalReader := messageDetails.UnverifiedBody if messageDetails.IsSigned && !dh.DisableAutomaticTextSanitize && len(messageDetails.SignatureCandidates) > 0 && messageDetails.SignatureCandidates[len(messageDetails.SignatureCandidates)-1].SigType == packet.SigTypeText { // TODO: This currently assumes that only one type of signature // can be present. internalReader = internal.NewSanitizeReader(internalReader) } return &VerifyDataReader{ messageDetails, internalReader, dh.VerifyKeyRing, config.Time().Unix(), dh.DisableVerifyTimeCheck, false, dh.VerificationContext, }, nil } func (dh *decryptionHandle) decryptStreamWithSession(dataPacketReader Reader) (plainMessage *VerifyDataReader, err error) { messageDetails, verifyTime, err := dh.decryptStreamWithSessionAndParse(dataPacketReader) if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in reading message") } // Add utf8 sanitizer if signature has type packet.SigTypeText internalReader := messageDetails.UnverifiedBody if messageDetails.IsSigned && !dh.DisableAutomaticTextSanitize && len(messageDetails.SignatureCandidates) > 0 && messageDetails.SignatureCandidates[len(messageDetails.SignatureCandidates)-1].SigType == packet.SigTypeText { // TODO: This currently assumes that only one type of signature // can be present. internalReader = internal.NewSanitizeReader(internalReader) } return &VerifyDataReader{ messageDetails, internalReader, dh.VerifyKeyRing, verifyTime, dh.DisableVerifyTimeCheck, false, dh.VerificationContext, }, err } func (dh *decryptionHandle) decryptStreamWithSessionAndParse(messageReader io.Reader) (*openpgp.MessageDetails, int64, error) { var keyring openpgp.EntityList var decrypted io.ReadCloser var selectedSessionKey *SessionKey var err error // Read symmetrically encrypted data packet for _, sessionKeyCandidate := range dh.SessionKeys { decrypted, err = decryptStreamWithSessionKey(sessionKeyCandidate, messageReader) if err == nil { // No error occurred selectedSessionKey = sessionKeyCandidate break } } if selectedSessionKey == nil { return nil, 0, errors.Wrap(err, "gopenpgp: unable to decrypt message with session key") } config := dh.decryptionConfig(dh.clock().Unix()) checkPacketSequence := false config.CheckPacketSequence = &checkPacketSequence if dh.VerificationContext != nil { config.KnownNotations = map[string]bool{constants.SignatureContextName: true} } // Push decrypted packet as literal packet and use openpgp's reader if dh.VerifyKeyRing != nil { keyring = append(keyring, dh.VerifyKeyRing.entities...) } if dh.DecryptionKeyRing != nil { keyring = append(keyring, dh.DecryptionKeyRing.entities...) } md, err := openpgp.ReadMessage(decrypted, keyring, nil, config) if err != nil { return nil, 0, errors.Wrap(err, "gopenpgp: unable to decode symmetric packet") } md.SessionKey = selectedSessionKey.Key md.UnverifiedBody = checkReader{decrypted, md.UnverifiedBody} return md, config.Time().Unix(), nil } func decryptStreamWithSessionKey(sessionKey *SessionKey, messageReader io.Reader) (io.ReadCloser, error) { var decrypted io.ReadCloser // Read symmetrically encrypted data packet Loop: for { packets := packet.NewReader(messageReader) p, err := packets.Next() if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to read symmetric packet") } // Decrypt data packet switch p := p.(type) { case *packet.EncryptedKey, *packet.SymmetricKeyEncrypted: // Ignore potential key packets continue case *packet.SymmetricallyEncrypted, *packet.AEADEncrypted: if symPacket, ok := p.(*packet.SymmetricallyEncrypted); ok { if !symPacket.IntegrityProtected { return nil, errors.New("gopenpgp: message is not authenticated") } } var dc packet.CipherFunction if !sessionKey.v6 { dc, err = sessionKey.GetCipherFunc() if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to decrypt with session key") } } encryptedDataPacket, isDataPacket := p.(packet.EncryptedDataPacket) if !isDataPacket { return nil, errors.Wrap(err, "gopenpgp: unknown data packet") } decrypted, err = encryptedDataPacket.Decrypt(dc, sessionKey.Key) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to decrypt symmetric packet") } break Loop default: return nil, errors.New("gopenpgp: invalid packet type") } } return decrypted, nil } func (dh *decryptionHandle) decryptStreamAndVerifyDetached(encryptedData, encryptedSignature Reader, isPlaintextSignature bool) (plainMessage *VerifyDataReader, err error) { verifyTime := dh.clock().Unix() var mdData *openpgp.MessageDetails signature := encryptedSignature // Decrypt both messages if len(dh.SessionKeys) > 0 { // Decrypt with session key. mdData, _, err = dh.decryptStreamWithSessionAndParse(encryptedData) if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in reading data message") } if !isPlaintextSignature { // Decrypting reader for the encrypted signature mdSig, _, err := dh.decryptStreamWithSessionAndParse(encryptedSignature) if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in reading detached signature message") } signature = mdSig.UnverifiedBody } } else { // Password or private keys config := dh.decryptionConfig(verifyTime) var entries openpgp.EntityList if dh.DecryptionKeyRing != nil { entries = append(entries, dh.DecryptionKeyRing.entities...) } // Decrypting reader for the encrypted data var selectedPassword []byte if len(dh.Passwords) > 0 { resetReader := internal.NewResetReader(encryptedData) for _, passwordCandidate := range dh.Passwords { prompt := createPasswordPrompt(passwordCandidate) mdData, err = openpgp.ReadMessage(resetReader, entries, prompt, config) if err == nil { // No error occurred selectedPassword = passwordCandidate resetReader.DisableBuffering() break } if _, err := resetReader.Reset(); err != nil { // Should not happen return nil, errors.Wrap(err, "gopenpgp: buffer reset failed") } } if selectedPassword == nil { return nil, errors.Wrap(err, "gopenpgp: error in reading data message: no password matched") } } else { mdData, err = openpgp.ReadMessage(encryptedData, entries, nil, config) if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in reading data message") } } if !isPlaintextSignature { // Decrypting reader for the encrypted signature prompt := createPasswordPrompt(selectedPassword) noCheckPacketSequence := false config.CheckPacketSequence = &noCheckPacketSequence mdSig, err := openpgp.ReadMessage(encryptedSignature, entries, prompt, config) if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in reading detached signature message") } signature = mdSig.UnverifiedBody } } config := dh.decryptionConfig(verifyTime) // Verifying reader that wraps the decryption readers to verify the signature sigVerifyReader, err := verifyingDetachedReader( mdData.UnverifiedBody, signature, dh.VerifyKeyRing, dh.VerificationContext, dh.DisableVerifyTimeCheck, dh.DisableAutomaticTextSanitize, config, NewConstantClock(verifyTime), ) if err != nil { return nil, err } // Update message details with information from the data of the pgp message sigVerifyReader.details.LiteralData = mdData.LiteralData sigVerifyReader.details.SessionKey = mdData.SessionKey return sigVerifyReader, nil } func getSignaturePacket(sig []byte) (*packet.Signature, error) { p, err := packet.Read(bytes.NewReader(sig)) if err != nil { return nil, err } sigPacket, ok := p.(*packet.Signature) if !ok { return nil, errors.Wrap(err, "gopenpgp: invalid signature packet") } return sigPacket, nil } func createPasswordPrompt(password []byte) func(keys []openpgp.Key, symmetric bool) ([]byte, error) { if password == nil { return nil } firstTimeCalled := true return func(keys []openpgp.Key, symmetric bool) ([]byte, error) { if firstTimeCalled { firstTimeCalled = false return password, nil } // Re-prompt still occurs if SKESK pasrsing fails (i.e. when decrypted cipher algo is invalid). // For most (but not all) cases, inputting a wrong passwords is expected to trigger this error. return nil, errors.New("gopenpgp: wrong password in symmetric decryption") } } func (dh *decryptionHandle) decryptionConfig(configTime int64) *packet.Config { config := dh.profile.EncryptionConfig() // Check intended recipients in signatures. checkIntendedRecipients := !dh.DisableIntendedRecipients config.CheckIntendedRecipients = &checkIntendedRecipients // Check for valid packet sequence checkPacketSequence := !dh.DisableStrictMessageParsing config.CheckPacketSequence = &checkPacketSequence // Allow message decryption of PGP messages with no integrity tag. config.InsecureAllowUnauthenticatedMessages = dh.InsecureDisableUnauthenticatedMessagesCheck // Allow message decryption with signature keys. if dh.InsecureAllowDecryptionWithSigningKeys { config.InsecureAllowDecryptionWithSigningKeys = dh.InsecureAllowDecryptionWithSigningKeys } // Should the session key be returned. config.CacheSessionKey = dh.RetrieveSessionKey // Set time. config.Time = NewConstantClock(configTime) return config } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/decryption_handle.go000066400000000000000000000227641472137411600261520ustar00rootroot00000000000000package crypto import ( "bytes" "github.com/ProtonMail/go-crypto/openpgp/armor" "github.com/ProtonMail/gopenpgp/v3/internal" "github.com/pkg/errors" ) // decryptionHandle collects the configuration parameters to decrypt a pgp message. // The fields in the struct allow to customize the decryption. type decryptionHandle struct { // DecryptionKeyRing provides the secret keys for decrypting the pgp message. // Assumes that the message was encrypted towards a public key in DecryptionKeyRing. // If nil, set another field for the type of decryption: SessionKey or Password DecryptionKeyRing *KeyRing // SessionKeys provides one or more session keys for decrypting the pgp message. // Assumes that the message was encrypted with one of the session keys provided. // If nil, set another field for the type of decryption: DecryptionKeyRing or Password SessionKeys []*SessionKey // Passwords provides passwords for decrypting the pgp message. // Assumes that the message was encrypted with on of the keys derived from the passwords. // If nil, set another field for the type of decryption: DecryptionKeyRing or SessionKey Passwords [][]byte // VerifyKeyRing provides a set of public keys to verify the signature of the pgp message, if any. // If nil, the signatures are not verified. VerifyKeyRing *KeyRing // VerificationContext provides a verification context for the signature of the pgp message, if any. // Only considered if VerifyKeyRing is not nil. VerificationContext *VerificationContext // PlainDetachedSignature indicates that all provided detached signatures are not encrypted. PlainDetachedSignature bool // DisableIntendedRecipients indicates if the signature verification should not check if // the decryption key matches the intended recipients of the message. // If disabled, the decryption throws no error in a non-matching case. DisableIntendedRecipients bool DisableVerifyTimeCheck bool DisableStrictMessageParsing bool DisableAutomaticTextSanitize bool InsecureDisableUnauthenticatedMessagesCheck bool InsecureAllowDecryptionWithSigningKeys bool RetrieveSessionKey bool IsUTF8 bool clock Clock profile EncryptionProfile } // --- Default decryption handle to build from func defaultDecryptionHandle(profile EncryptionProfile, clock Clock) *decryptionHandle { return &decryptionHandle{ clock: clock, profile: profile, } } // --- Implements PGPDecryption interface // DecryptingReader returns a wrapper around underlying encryptedMessage Reader, // such that any read-operation via the wrapper results in a read from the decrypted pgp message. // The returned VerifyDataReader has to be fully read before any potential signatures can be verified. // Either read the message fully end then call VerifySignature or use the helper method ReadAllAndVerifySignature. // The encoding indicates if the input message should be unarmored or not, i.e., Bytes/Armor/Auto // where Auto tries to detect automatically. // If encryptedMessage is of type PGPSplitReader, the method tries to verify an encrypted detached signature // that is read from the separate reader. func (dh *decryptionHandle) DecryptingReader(encryptedMessage Reader, encoding int8) (plainMessageReader *VerifyDataReader, err error) { err = dh.validate() if err != nil { return } pgpSplitReader := isPGPSplitReader(encryptedMessage) if pgpSplitReader != nil { return dh.decryptingReader(pgpSplitReader, pgpSplitReader.Signature(), encoding) } return dh.decryptingReader(encryptedMessage, nil, encoding) } // Decrypt decrypts an encrypted pgp message. // Returns a VerifiedDataResult, which can be queried for potential signature verification errors, // and the plaintext data. Note that on a signature error, the method does not return an error. // Instead, the signature error is stored within the VerifiedDataResult. // The encoding indicates if the input message should be unarmored or not, i.e., Bytes/Armor/Auto // where Auto tries to detect automatically. func (dh *decryptionHandle) Decrypt(pgpMessage []byte, encoding int8) (*VerifiedDataResult, error) { messageReader := bytes.NewReader(pgpMessage) plainMessageReader, err := dh.DecryptingReader(messageReader, encoding) if err != nil { return nil, err } return plainMessageReader.ReadAllAndVerifySignature() } // DecryptDetached provides the same functionality as Decrypt but allows // to supply an encrypted detached signature that should be decrypted and verified // against the data in the pgp message. If encDetachedSignature is nil, the behavior is similar // to Decrypt. The encoding indicates if the input message should be unarmored or not, // i.e., Bytes/Armor/Auto where Auto tries to detect automatically. func (dh *decryptionHandle) DecryptDetached(pgpMessage []byte, encryptedDetachedSig []byte, encoding int8) (*VerifiedDataResult, error) { reader := &pgpSplitReader{ encMessage: bytes.NewReader(pgpMessage), } if encryptedDetachedSig != nil { reader.encSignature = bytes.NewReader(encryptedDetachedSig) } verifier, err := dh.DecryptingReader(reader, encoding) if err != nil { return nil, err } return verifier.ReadAllAndVerifySignature() } // DecryptSessionKey decrypts an encrypted session key. // To decrypted a session key, the decryption handle must contain either a decryption key or a password. func (dh *decryptionHandle) DecryptSessionKey(keyPackets []byte) (sk *SessionKey, err error) { switch { case len(dh.Passwords) > 0: for _, passwordCandidate := range dh.Passwords { sk, err = decryptSessionKeyWithPassword(keyPackets, passwordCandidate) if err == nil { return sk, nil } } return nil, err case dh.DecryptionKeyRing != nil: return decryptSessionKey(dh.DecryptionKeyRing, keyPackets) } return nil, errors.New("gopenpgp: no decryption key or password provided") } // ClearPrivateParams clears all private key material contained in EncryptionHandle from memory. func (dh *decryptionHandle) ClearPrivateParams() { if dh.DecryptionKeyRing != nil { dh.DecryptionKeyRing.ClearPrivateParams() } if len(dh.SessionKeys) > 0 { for _, sk := range dh.SessionKeys { sk.Clear() } } if len(dh.Passwords) > 0 { for _, password := range dh.Passwords { clearMem(password) } } } func (dh *decryptionHandle) validate() error { if dh.DecryptionKeyRing == nil && len(dh.Passwords) == 0 && len(dh.SessionKeys) == 0 { return errors.New("gopenpgp: no decryption key material provided") } return nil } func (dh *decryptionHandle) decryptingReader(encryptedMessage Reader, encryptedSignature Reader, encoding int8) (plainMessageReader *VerifyDataReader, err error) { err = dh.validate() if err != nil { return nil, err } var armored bool encryptedMessage, armored = unarmorInput(encoding, encryptedMessage) var armoredBlock *armor.Block if armored { // Wrap encryptedMessage with decode armor reader. armoredBlock, err = armor.Decode(encryptedMessage) if err != nil { err = errors.Wrap(err, "gopenpgp: unarmor failed for pgp message") return nil, err } encryptedMessage = armoredBlock.Body } if encryptedSignature != nil { encryptedSignature, armored = unarmorInput(encoding, encryptedSignature) if armored { // Wrap encryptedSignature with decode armor reader. armoredBlock, err = armor.Decode(encryptedSignature) if err != nil { err = errors.Wrap(err, "gopenpgp: unarmor failed for pgp encrypted signature message") return nil, err } encryptedSignature = armoredBlock.Body if dh.PlainDetachedSignature && armoredBlock.Type != "PGP SIGNATURE" { err = errors.New("gopenpgp: detached signature is not plaintext") return nil, err } if !dh.PlainDetachedSignature && armoredBlock.Type != "PGP MESSAGE" { err = errors.New("gopenpgp: encrypted detached signature is not an encrypted pgp message") return nil, err } } } var decryptionTried bool if len(dh.SessionKeys) > 0 { // Decrypt with session key. if encryptedSignature != nil { plainMessageReader, err = dh.decryptStreamAndVerifyDetached(encryptedMessage, encryptedSignature, dh.PlainDetachedSignature) } else { plainMessageReader, err = dh.decryptStreamWithSession(encryptedMessage) } decryptionTried = true } if (!decryptionTried || err != nil) && dh.DecryptionKeyRing != nil { // Decrypt with keyring. if encryptedSignature != nil { plainMessageReader, err = dh.decryptStreamAndVerifyDetached(encryptedMessage, encryptedSignature, dh.PlainDetachedSignature) } else { plainMessageReader, err = dh.decryptStream(encryptedMessage) } decryptionTried = true } if (!decryptionTried || err != nil) && len(dh.Passwords) > 0 { // Decrypt with password. if encryptedSignature != nil { plainMessageReader, err = dh.decryptStreamAndVerifyDetached(encryptedMessage, encryptedSignature, dh.PlainDetachedSignature) } else { plainMessageReader, err = dh.decryptStream(encryptedMessage) } decryptionTried = true } if !decryptionTried { // No decryption material provided. err = errors.New("gopenpgp: no decryption key ring, session key, or password provided") } if err != nil { return nil, err } if dh.IsUTF8 { plainMessageReader.internalReader = internal.NewSanitizeReader(plainMessageReader.internalReader) } return plainMessageReader, nil } func isPGPSplitReader(w Reader) PGPSplitReader { v, ok := interface{}(w).(PGPSplitReader) if ok { return v } v, ok = interface{}(&w).(PGPSplitReader) if ok { return v } return nil } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/decryption_handle_builder.go000066400000000000000000000205541472137411600276530ustar00rootroot00000000000000package crypto // DecryptionHandleBuilder allows to configure a decryption handle // to decrypt a pgp message. type DecryptionHandleBuilder struct { handle *decryptionHandle defaultClock Clock err error profile EncryptionProfile } func newDecryptionHandleBuilder(profile EncryptionProfile, clock Clock) *DecryptionHandleBuilder { return &DecryptionHandleBuilder{ handle: defaultDecryptionHandle(profile, clock), defaultClock: clock, profile: profile, } } // DecryptionKeys sets the secret keys for decrypting the pgp message. // Assumes that the message was encrypted towards one of the secret keys. // Triggers the hybrid decryption mode. // If not set, set another field for the type of decryption: SessionKey or Password. func (dpb *DecryptionHandleBuilder) DecryptionKeys(decryptionKeyRing *KeyRing) *DecryptionHandleBuilder { dpb.handle.DecryptionKeyRing = decryptionKeyRing return dpb } func (dpb *DecryptionHandleBuilder) DecryptionKey(decryptionKey *Key) *DecryptionHandleBuilder { var err error if dpb.handle.DecryptionKeyRing == nil { dpb.handle.DecryptionKeyRing, err = NewKeyRing(decryptionKey) } else { err = dpb.handle.DecryptionKeyRing.AddKey(decryptionKey) } dpb.err = err return dpb } // SessionKey sets a session key for decrypting the pgp message. // Assumes that the message was encrypted with session key provided. // Triggers the session key decryption mode. // If not set, set another field for the type of decryption: DecryptionKeys or Password. func (dpb *DecryptionHandleBuilder) SessionKey(sessionKey *SessionKey) *DecryptionHandleBuilder { dpb.handle.SessionKeys = []*SessionKey{sessionKey} return dpb } // SessionKeys sets multiple session keys for decrypting the pgp message. // Assumes that the message was encrypted with one of the session keys provided. // Triggers the session key decryption mode. // If not set, set another field for the type of decryption: DecryptionKeys or Password. // Not supported on go-mobile clients. func (dpb *DecryptionHandleBuilder) SessionKeys(sessionKeys []*SessionKey) *DecryptionHandleBuilder { dpb.handle.SessionKeys = sessionKeys return dpb } // Password sets a password that is used to derive a key to decrypt the pgp message. // Assumes that the message was encrypted with a key derived from the password. // Triggers the password decryption mode. // If not set, set another field for the type of decryption: DecryptionKeys or SessionKey. func (dpb *DecryptionHandleBuilder) Password(password []byte) *DecryptionHandleBuilder { dpb.handle.Passwords = [][]byte{password} return dpb } // Passwords sets passwords that are used to derive keys to decrypt the pgp message. // Assumes that the message was encrypted with one of the keys derived from the passwords. // Triggers the password decryption mode. // If not set, set another field for the type of decryption: DecryptionKeys or SessionKey. // Not supported on go-mobile clients. func (dpb *DecryptionHandleBuilder) Passwords(passwords [][]byte) *DecryptionHandleBuilder { dpb.handle.Passwords = passwords return dpb } // VerificationKeys sets the public keys for verifying the signatures of the pgp message, if any. // If not set, the signatures cannot be verified. func (dpb *DecryptionHandleBuilder) VerificationKeys(keys *KeyRing) *DecryptionHandleBuilder { dpb.handle.VerifyKeyRing = keys return dpb } // VerificationKey sets the public key for verifying the signatures of the pgp message, if any. // If not set, the signatures cannot be verified. func (dpb *DecryptionHandleBuilder) VerificationKey(key *Key) *DecryptionHandleBuilder { var err error if dpb.handle.VerifyKeyRing == nil { dpb.handle.VerifyKeyRing, err = NewKeyRing(key) } else { err = dpb.handle.VerifyKeyRing.AddKey(key) } dpb.err = err return dpb } // VerificationContext sets a verification context for signatures of the pgp message, if any. // Only considered if VerifyKeys are set. func (dpb *DecryptionHandleBuilder) VerificationContext(verifyContext *VerificationContext) *DecryptionHandleBuilder { dpb.handle.VerificationContext = verifyContext return dpb } // VerifyTime sets the verification time to the provided timestamp. // If not set, the systems current time is used for signature verification. func (dpb *DecryptionHandleBuilder) VerifyTime(unixTime int64) *DecryptionHandleBuilder { dpb.handle.clock = NewConstantClock(unixTime) return dpb } // Utf8 indicates if the output plaintext is Utf8 and // should be sanitized from canonicalised line endings. func (dpb *DecryptionHandleBuilder) Utf8() *DecryptionHandleBuilder { dpb.handle.IsUTF8 = true return dpb } // PlainDetachedSignature indicates that the detached signature to verify is not decrypted // and can be verified as is. func (dpb *DecryptionHandleBuilder) PlainDetachedSignature() *DecryptionHandleBuilder { dpb.handle.PlainDetachedSignature = true return dpb } // DisableVerifyTimeCheck disables the check for comparing the signature creation time // against the verification time. func (dpb *DecryptionHandleBuilder) DisableVerifyTimeCheck() *DecryptionHandleBuilder { dpb.handle.DisableVerifyTimeCheck = true return dpb } // DisableStrictMessageParsing disables the check that decryption inputs conform // to the OpenPGP Message grammar. // If set, the decryption methods return no error if the message does not conform to the // OpenPGP message grammar. func (dpb *DecryptionHandleBuilder) DisableStrictMessageParsing() *DecryptionHandleBuilder { dpb.handle.DisableStrictMessageParsing = true return dpb } // DisableIntendedRecipients indicates if the signature verification should not check if // the decryption key matches the intended recipients of the message. // If disabled, the decryption methods throw no error in a non-matching case. func (dpb *DecryptionHandleBuilder) DisableIntendedRecipients() *DecryptionHandleBuilder { dpb.handle.DisableIntendedRecipients = true return dpb } // DisableAutomaticTextSanitize indicates that automatic text sanitization should be disabled. // If not disabled, the output will be sanitized if a text signature is present. func (dpb *DecryptionHandleBuilder) DisableAutomaticTextSanitize() *DecryptionHandleBuilder { dpb.handle.DisableAutomaticTextSanitize = true return dpb } // InsecureDisableUnauthenticatedMessagesCheck enables to read // encrypted messages without Modification Detection Code (MDC). // MDC is mandated by the latest standard and has long been implemented // in most OpenPGP implementations. Messages without MDC are considered unnecessarily // insecure and should be prevented whenever possible. // In case one needs to deal with messages from very old OpenPGP implementations, there // might be no other way than to tolerate the missing MDC. Setting this flag, allows this // mode of operation. It should be considered a measure of last resort. // SECURITY HAZARD: Use with care. func (dpb *DecryptionHandleBuilder) InsecureDisableUnauthenticatedMessagesCheck() *DecryptionHandleBuilder { dpb.handle.InsecureDisableUnauthenticatedMessagesCheck = true return dpb } // InsecureAllowDecryptionWithSigningKeys enables decryption of messages using keys // that are designated solely as signing keys. // While using the same key for both encryption and signing is discouraged // due to reduced security, this flag is useful for decrypting legacy messages. // This is because some older libraries did not respect key flags when // selecting a key for encryption. // SECURITY HAZARD: Use with care. func (dpb *DecryptionHandleBuilder) InsecureAllowDecryptionWithSigningKeys() *DecryptionHandleBuilder { dpb.handle.InsecureAllowDecryptionWithSigningKeys = true return dpb } // RetrieveSessionKey sets the flag to indicate if the session key used for decryption // should be returned to the caller of the decryption function. func (dpb *DecryptionHandleBuilder) RetrieveSessionKey() *DecryptionHandleBuilder { dpb.handle.RetrieveSessionKey = true return dpb } // New creates a DecryptionHandle and checks that the given // combination of parameters is valid. If one of the parameters are invalid // the latest error is returned. func (dpb *DecryptionHandleBuilder) New() (PGPDecryption, error) { if dpb.err != nil { return nil, dpb.err } dpb.err = dpb.handle.validate() if dpb.err != nil { return nil, dpb.err } handle := dpb.handle dpb.handle = defaultDecryptionHandle(dpb.profile, dpb.defaultClock) return handle, nil } func (dpb *DecryptionHandleBuilder) Error() error { return dpb.err } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/encoding.go000066400000000000000000000010731472137411600242330ustar00rootroot00000000000000package crypto import ( "io" armorHelper "github.com/ProtonMail/gopenpgp/v3/armor" ) type PGPEncoding int8 // PGPEncoding determines the message encoding. // The type is int8 for compatibility with gomobile. const ( Armor int8 = 0 Bytes int8 = 1 // Default for other int8 values. Auto int8 = 2 ) func armorOutput(e int8) bool { return e == Armor } func unarmorInput(e int8, input io.Reader) (reader Reader, unarmor bool) { reader = input switch e { case Armor: unarmor = true case Auto: reader, unarmor = armorHelper.IsPGPArmored(input) } return } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/encrypt_decrypt_err_test.go000066400000000000000000000151311472137411600275720ustar00rootroot00000000000000package crypto import ( "testing" ) const wrongTestContext = "wrong-context" var wrongPassword = []byte("wrong-password") func TestDecryptWrongKey(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). Recipients(material.keyRingTestPublic). SigningKeys(material.keyRingTestPrivate). New() decHandle, _ := material.pgp.Decryption(). DecryptionKey(material.keyWrong). New() pgpMessage, err := encHandle.Encrypt([]byte(testMessage)) if err != nil { t.Fatal(err) } if _, err = decHandle.Decrypt(pgpMessage.Bytes(), Bytes); err == nil { t.Fatal("should not decrypt with wrong key") } }) } } func TestDecryptWrongPassword(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). Password(password). New() decHandle, _ := material.pgp.Decryption(). Password(wrongPassword). New() pgpMessage, err := encHandle.Encrypt([]byte(testMessage)) if err != nil { t.Fatal(err) } if _, err = decHandle.Decrypt(pgpMessage.Bytes(), Bytes); err == nil { t.Fatal("should not decrypt with wrong password") } }) } } func TestDecryptWrongSessionKey(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { wrongSessionKeyBytes := make([]byte, len(material.testSessionKey.Key)) copy(wrongSessionKeyBytes, material.testSessionKey.Key) wrongSessionKeyBytes[0] += 1 wrongSessionKey := NewSessionKeyFromToken(wrongSessionKeyBytes, material.testSessionKey.Algo) encHandle, _ := material.pgp.Encryption(). SessionKey(material.testSessionKey). New() decHandle, _ := material.pgp.Decryption(). SessionKey(wrongSessionKey). New() pgpMessage, err := encHandle.Encrypt([]byte(testMessage)) if err != nil { t.Fatal(err) } if _, err = decHandle.Decrypt(pgpMessage.Bytes(), Bytes); err == nil { t.Fatal("Should not decrypt with wrong session key") } }) } } func TestDecryptVerifyWrongKey(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). Recipients(material.keyRingTestPublic). SigningKey(material.keyWrong). New() decHandle, _ := material.pgp.Decryption(). DecryptionKeys(material.keyRingTestPrivate). VerificationKeys(material.keyRingTestPublic). New() testVerificationFails( t, encHandle, decHandle, "Signature verification must fail with wrong key", ) }) } } func TestDecryptVerifyWrongContext(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). Recipients(material.keyRingTestPublic). SigningKeys(material.keyRingTestPrivate). SigningContext(NewSigningContext(testContext, true)). New() decHandle, _ := material.pgp.Decryption(). DecryptionKeys(material.keyRingTestPrivate). VerificationKeys(material.keyRingTestPublic). VerificationContext(NewVerificationContext(wrongTestContext, true, 0)). New() testVerificationFails( t, encHandle, decHandle, "Signature verification must fail with wrong context", ) }) } } func TestDecryptVerifyWrongContextMissing(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). Recipients(material.keyRingTestPublic). SigningKeys(material.keyRingTestPrivate). SigningContext(NewSigningContext(testContext, true)). New() decHandle, _ := material.pgp.Decryption(). DecryptionKeys(material.keyRingTestPrivate). VerificationKeys(material.keyRingTestPublic). New() testVerificationFails( t, encHandle, decHandle, "Signature verification must fail with no context", ) }) } } func TestDecryptVerifyNoContextButRequired(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). Recipients(material.keyRingTestPublic). SigningKeys(material.keyRingTestPrivate). New() decHandle, _ := material.pgp.Decryption(). DecryptionKeys(material.keyRingTestPrivate). VerificationKeys(material.keyRingTestPublic). VerificationContext(NewVerificationContext(wrongTestContext, true, 0)). New() testVerificationFails( t, encHandle, decHandle, "Signature verification must fail with no context", ) }) } } func TestDecryptVerifyNoCriticalContext(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). Recipients(material.keyRingTestPublic). SigningKeys(material.keyRingTestPrivate). SigningContext(NewSigningContext(testContext, false)). New() decHandle, _ := material.pgp.Decryption(). DecryptionKeys(material.keyRingTestPrivate). VerificationKeys(material.keyRingTestPublic). New() testVerificationSuccess(t, encHandle, decHandle) }) } } func TestDecryptVerifyNoCriticalContextVerify(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). Recipients(material.keyRingTestPublic). SigningKeys(material.keyRingTestPrivate). New() decHandle, _ := material.pgp.Decryption(). DecryptionKeys(material.keyRingTestPrivate). VerificationKeys(material.keyRingTestPublic). VerificationContext(NewVerificationContext(testContext, false, 0)). New() testVerificationSuccess(t, encHandle, decHandle) }) } } func testVerificationFails( t *testing.T, encHandle PGPEncryption, decHandle PGPDecryption, failure string, ) { pgpMessage, err := encHandle.Encrypt([]byte(testMessage)) if err != nil { t.Fatal(err) } verifyResult, err := decHandle.Decrypt(pgpMessage.Bytes(), Bytes) if err != nil { t.Fatal(err) } if verifyResult.SignatureError() == nil { t.Fatal(failure) } } func testVerificationSuccess( t *testing.T, encHandle PGPEncryption, decHandle PGPDecryption, ) { pgpMessage, err := encHandle.Encrypt([]byte(testMessage)) if err != nil { t.Fatal(err) } verifyResult, err := decHandle.Decrypt(pgpMessage.Bytes(), Bytes) if err != nil { t.Fatal(err) } if verifyResult.SignatureError() != nil { t.Fatal("Expected no signature failure") } } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/encrypt_decrypt_test.go000066400000000000000000001077061472137411600267340ustar00rootroot00000000000000package crypto import ( "bytes" "fmt" "io" "os" "reflect" "regexp" "strings" "testing" openpgp "github.com/ProtonMail/go-crypto/openpgp/v2" "github.com/ProtonMail/gopenpgp/v3/profile" "github.com/stretchr/testify/assert" ) const testMessageString = "Hello World!" const testMessageUTF8 = "Hell\ro World!\nmore\neven more\n" const testContext = "test-context" var password = []byte("password") var decPasswords = [][]byte{[]byte("wrongPassword"), password} var testMaterialForProfiles []*testMaterial func generateTestKeyMaterial(name string, profile *profile.Custom) *testMaterial { handle := PGPWithProfile(profile) testSessionKey, err := handle.GenerateSessionKey() if err != nil { panic("Cannot generate session key:" + err.Error()) } keyTest, err := handle.KeyGeneration(). AddUserId("test", "test@test.test"). New(). GenerateKey() if err != nil { panic("Cannot generate key:" + err.Error()) } keyTestPublic, err := keyTest.ToPublic() if err != nil { panic("Cannot extract public key:" + err.Error()) } keyRingTestPrivate, err := NewKeyRing(keyTest) if err != nil { panic("Cannot create keyring:" + err.Error()) } keyRingTestPublic, err := NewKeyRing(keyTestPublic) if err != nil { panic("Cannot create keyring:" + err.Error()) } keyWrong, err := handle.KeyGeneration(). AddUserId("testWrong", "testWrong@test.test"). New(). GenerateKey() if err != nil { panic("Cannot generate key:" + err.Error()) } return &testMaterial{ profileName: name, pgp: handle, keyRingTestPublic: keyRingTestPublic, keyRingTestPrivate: keyRingTestPrivate, testSessionKey: testSessionKey, keyWrong: keyWrong, } } func initEncDecTest() { for ind, profile := range testProfiles { material := generateTestKeyMaterial(testProfileNames[ind], profile) testMaterialForProfiles = append(testMaterialForProfiles, material) } if len(testMaterialForProfiles) < 2 { return } firstMaterial := testMaterialForProfiles[0] lastMaterial := testMaterialForProfiles[len(testMaterialForProfiles)-1] // Mixed keys with different profiles mixKeyringPriv := &KeyRing{ entities: openpgp.EntityList{ firstMaterial.keyRingTestPrivate.entities[0], lastMaterial.keyRingTestPrivate.entities[0], }, } mixKeyringPub := &KeyRing{ entities: openpgp.EntityList{ firstMaterial.keyRingTestPublic.entities[0], lastMaterial.keyRingTestPublic.entities[0], }, } mixedTestMaterial := &testMaterial{ profileName: fmt.Sprintf("mixed(%s)(%s)", firstMaterial.profileName, lastMaterial.profileName), pgp: lastMaterial.pgp, keyRingTestPublic: mixKeyringPub, keyRingTestPrivate: mixKeyringPriv, testSessionKey: lastMaterial.testSessionKey, } testMaterialForProfiles = append(testMaterialForProfiles, mixedTestMaterial) } type testMaterial struct { profileName string pgp *PGPHandle keyRingTestPublic *KeyRing keyRingTestPrivate *KeyRing keyWrong *Key testSessionKey *SessionKey } func TestEncryptDecryptStream(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). Recipients(material.keyRingTestPublic). SigningKeys(material.keyRingTestPrivate). New() decHandle, _ := material.pgp.Decryption(). DecryptionKeys(material.keyRingTestPrivate). VerificationKeys(material.keyRingTestPublic). New() testEncryptDecryptStream( t, []byte(testMessageString), nil, encHandle, decHandle, len(material.keyRingTestPrivate.entities), Bytes, ) }) } } func TestEncryptDecryptStreamWithContext(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). Recipients(material.keyRingTestPublic). SigningKeys(material.keyRingTestPrivate). SigningContext(NewSigningContext(testContext, true)). New() decHandle, _ := material.pgp.Decryption(). DecryptionKeys(material.keyRingTestPrivate). VerificationKeys(material.keyRingTestPublic). VerificationContext(NewVerificationContext(testContext, true, 0)). New() testEncryptDecryptStream( t, []byte(testMessageString), nil, encHandle, decHandle, len(material.keyRingTestPrivate.entities), Bytes, ) }) } } func TestEncryptDecryptStreamWithContextAndCompression(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). Recipients(material.keyRingTestPublic). SigningKeys(material.keyRingTestPrivate). SigningContext(NewSigningContext(testContext, true)). Compress(). New() decHandle, _ := material.pgp.Decryption(). DecryptionKeys(material.keyRingTestPrivate). VerificationKeys(material.keyRingTestPublic). VerificationContext(NewVerificationContext(testContext, true, 0)). New() testEncryptDecryptStream( t, []byte(testMessageString), nil, encHandle, decHandle, len(material.keyRingTestPrivate.entities), Bytes, ) }) } } func TestEncryptDecryptStreamWithCachedSession(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). Recipients(material.keyRingTestPublic). SigningKeys(material.keyRingTestPrivate). SessionKey(material.testSessionKey). New() decHandle, _ := material.pgp.Decryption(). SessionKey(material.testSessionKey). VerificationKeys(material.keyRingTestPublic). DisableIntendedRecipients(). New() testEncryptDecryptStream( t, []byte(testMessageString), nil, encHandle, decHandle, len(material.keyRingTestPrivate.entities), Bytes, ) }) } } func TestEncryptDecryptCachedSessionOnDecrypt(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). Recipients(material.keyRingTestPublic). SigningKeys(material.keyRingTestPrivate). SessionKey(material.testSessionKey). New() decHandle, _ := material.pgp.Decryption(). DecryptionKeys(material.keyRingTestPrivate). VerificationKeys(material.keyRingTestPublic). RetrieveSessionKey(). New() pgpMessage, err := encHandle.Encrypt([]byte(testMessageString)) if err != nil { t.Fatal("Expected no error in encryption, got:", err) } decResult, err := decHandle.Decrypt(pgpMessage.Bytes(), Bytes) if err != nil { t.Fatal("Expected no error in decryption, got:", decResult) } if !bytes.Equal(decResult.SessionKey().Key, material.testSessionKey.Key) { t.Fatal("Expected the cached session key to be equal") } if decResult.SessionKey().Algo != material.testSessionKey.Algo { t.Fatal("Expected the session key algorithms to be equal") } decHandle, _ = material.pgp.Decryption(). DecryptionKeys(material.keyRingTestPrivate). VerificationKeys(material.keyRingTestPublic). New() decResult, err = decHandle.Decrypt(pgpMessage.Bytes(), Bytes) if err != nil { t.Fatal("Expected no error in decryption, got:", decResult) } if decResult.SessionKey() != nil { t.Fatal("Expected no cached session key") } }) } } func TestSessionEncryptDecryptStream(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). SessionKey(material.testSessionKey). SigningKeys(material.keyRingTestPrivate). New() decHandle, _ := material.pgp.Decryption(). SessionKey(material.testSessionKey). VerificationKeys(material.keyRingTestPublic). New() testEncryptDecryptStream( t, []byte(testMessageString), nil, encHandle, decHandle, len(material.keyRingTestPrivate.entities), Bytes, ) }) } } func TestSessionEncryptDecryptStreamWithContext(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). SessionKey(material.testSessionKey). SigningKeys(material.keyRingTestPrivate). SigningContext(NewSigningContext(testContext, true)). New() decHandle, _ := material.pgp.Decryption(). SessionKey(material.testSessionKey). VerificationKeys(material.keyRingTestPublic). VerificationContext(NewVerificationContext(testContext, true, 0)). New() testEncryptDecryptStream( t, []byte(testMessageString), nil, encHandle, decHandle, len(material.keyRingTestPrivate.entities), Bytes, ) }) } } func TestSessionEncryptDecryptStreamWithContextAndCompression(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). SessionKey(material.testSessionKey). SigningKeys(material.keyRingTestPrivate). SigningContext(NewSigningContext(testContext, true)). Compress(). New() decHandle, _ := material.pgp.Decryption(). SessionKey(material.testSessionKey). VerificationKeys(material.keyRingTestPublic). VerificationContext(NewVerificationContext(testContext, true, 0)). New() testEncryptDecryptStream( t, []byte(testMessageString), nil, encHandle, decHandle, len(material.keyRingTestPrivate.entities), Bytes, ) }) } } func TestEncryptDecryptStreamArmored(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). Recipients(material.keyRingTestPublic). SigningKeys(material.keyRingTestPrivate). New() decHandle, _ := material.pgp.Decryption(). DecryptionKeys(material.keyRingTestPrivate). VerificationKeys(material.keyRingTestPublic). New() testEncryptDecryptStream( t, []byte(testMessageString), nil, encHandle, decHandle, len(material.keyRingTestPrivate.entities), Armor, ) }) } } func TestEncryptDecryptSignUTF8Stream(t *testing.T) { for _, material := range testMaterialForProfiles { metadata := &LiteralMetadata{ isUTF8: true, } t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). Recipients(material.keyRingTestPublic). SigningKeys(material.keyRingTestPrivate). Utf8(). New() decHandle, _ := material.pgp.Decryption(). DecryptionKeys(material.keyRingTestPrivate). VerificationKeys(material.keyRingTestPublic). New() testEncryptDecryptStream( t, []byte(testMessageUTF8), metadata, encHandle, decHandle, len(material.keyRingTestPrivate.entities), Bytes, ) }) } } func TestEncryptDecryptUTF8Stream(t *testing.T) { for _, material := range testMaterialForProfiles { metadata := &LiteralMetadata{ isUTF8: true, } t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). Recipients(material.keyRingTestPublic). Utf8(). New() decHandle, _ := material.pgp.Decryption(). DecryptionKeys(material.keyRingTestPrivate). Utf8(). New() testEncryptDecryptStream( t, []byte(testMessageUTF8), metadata, encHandle, decHandle, 0, Bytes, ) }) } } func TestAEADDecryptionStream(t *testing.T) { pgpMessageDataReader, err := os.Open("testdata/gpg2.3-aead-pgp-message.pgp") if err != nil { t.Fatal("Expected no error when reading message data, got:", err) } aeadKey, err := NewKeyFromArmored(readTestFile("gpg2.3-aead-test-key.asc", false)) if err != nil { t.Fatal("Expected no error when unarmoring key, got:", err) } aeadKeyUnlocked, err := aeadKey.Unlock([]byte("test")) if err != nil { t.Fatal("Expected no error when unlocking, got:", err) } kR, err := NewKeyRing(aeadKeyUnlocked) if err != nil { t.Fatal("Expected no error when creating the keyring, got:", err) } defer kR.ClearPrivateParams() decHandle, _ := PGP().Decryption().DecryptionKeys(kR).New() messageReader, err := decHandle.DecryptingReader(pgpMessageDataReader, Auto) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } plaintext, err := messageReader.ReadAll() if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, "hello world\n", string(plaintext)) } func TestEncryptDecryptSplitStream(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). Recipients(material.keyRingTestPublic). SigningKeys(material.keyRingTestPrivate). New() decHandle, _ := material.pgp.Decryption(). DecryptionKeys(material.keyRingTestPrivate). VerificationKeys(material.keyRingTestPublic). New() testEncryptSplitDecryptStream( t, []byte(testMessageString), nil, encHandle, decHandle, splitWriter, len(material.keyRingTestPrivate.entities), Bytes, ) }) } } func TestEncryptDecryptSplitStreamWithContext(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). Recipients(material.keyRingTestPublic). SigningKeys(material.keyRingTestPrivate). SigningContext(NewSigningContext(testContext, true)). New() decHandle, _ := material.pgp.Decryption(). DecryptionKeys(material.keyRingTestPrivate). VerificationKeys(material.keyRingTestPublic). VerificationContext(NewVerificationContext(testContext, true, 0)). New() testEncryptSplitDecryptStream( t, []byte(testMessageString), nil, encHandle, decHandle, splitWriter, len(material.keyRingTestPrivate.entities), Bytes, ) }) } } func TestEncryptDecryptSplitStreamWithContextAndCompression(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). Recipients(material.keyRingTestPublic). SigningKeys(material.keyRingTestPrivate). SigningContext(NewSigningContext(testContext, true)). Compress(). New() decHandle, _ := material.pgp.Decryption(). DecryptionKeys(material.keyRingTestPrivate). VerificationKeys(material.keyRingTestPublic). VerificationContext(NewVerificationContext(testContext, true, 0)). New() testEncryptSplitDecryptStream( t, []byte(testMessageString), nil, encHandle, decHandle, splitWriter, len(material.keyRingTestPrivate.entities), Bytes, ) }) } } func TestSessionEncryptDecryptSplitStream(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). SessionKey(material.testSessionKey). SigningKeys(material.keyRingTestPrivate). New() decHandle, _ := material.pgp.Decryption(). SessionKey(material.testSessionKey). VerificationKeys(material.keyRingTestPublic). New() testEncryptSplitDecryptStream( t, []byte(testMessageString), nil, encHandle, decHandle, splitWriter, len(material.keyRingTestPrivate.entities), Bytes, ) }) } } func TestSessionEncryptDecryptSplitStreamWithContext(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). SessionKey(material.testSessionKey). SigningKeys(material.keyRingTestPrivate). SigningContext(NewSigningContext(testContext, true)). New() decHandle, _ := material.pgp.Decryption(). SessionKey(material.testSessionKey). VerificationKeys(material.keyRingTestPublic). VerificationContext(NewVerificationContext(testContext, true, 0)). New() testEncryptSplitDecryptStream( t, []byte(testMessageString), nil, encHandle, decHandle, splitWriter, len(material.keyRingTestPrivate.entities), Bytes, ) }) } } func TestSessionEncryptDecryptSplitStreamWithContextAndCompression(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). SessionKey(material.testSessionKey). SigningKeys(material.keyRingTestPrivate). SigningContext(NewSigningContext(testContext, true)). Compress(). New() decHandle, _ := material.pgp.Decryption(). SessionKey(material.testSessionKey). VerificationKeys(material.keyRingTestPublic). VerificationContext(NewVerificationContext(testContext, true, 0)). New() testEncryptSplitDecryptStream( t, []byte(testMessageString), nil, encHandle, decHandle, splitWriter, len(material.keyRingTestPrivate.entities), Bytes, ) }) } } func TestEncryptDecryptDetached(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). Recipients(material.keyRingTestPublic). SigningKeys(material.keyRingTestPrivate). DetachedSignature(). New() decHandle, _ := material.pgp.Decryption(). DecryptionKeys(material.keyRingTestPrivate). VerificationKeys(material.keyRingTestPublic). New() testEncryptSplitDecryptStream( t, []byte(testMessageString), nil, encHandle, decHandle, splitWriterDetachedSignature, len(material.keyRingTestPrivate.entities), Bytes, ) }) } } func TestPasswordEncryptDecryptDetached(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). Password(password). SigningKeys(material.keyRingTestPrivate). DetachedSignature(). New() decHandle, _ := material.pgp.Decryption(). Passwords(decPasswords). VerificationKeys(material.keyRingTestPublic). New() testEncryptSplitDecryptStream( t, []byte(testMessageString), nil, encHandle, decHandle, splitWriterDetachedSignature, len(material.keyRingTestPrivate.entities), Bytes, ) }) } } func TestSessionKeyEncryptDecryptDetached(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). SessionKey(material.testSessionKey). SigningKeys(material.keyRingTestPrivate). DetachedSignature(). New() decHandle, _ := material.pgp.Decryption(). SessionKey(material.testSessionKey). VerificationKeys(material.keyRingTestPublic). New() testEncryptSplitDecryptStream( t, []byte(testMessageString), nil, encHandle, decHandle, splitWriterDetachedSignature, len(material.keyRingTestPrivate.entities), Bytes, ) }) } } func TestEncryptDecryptPlaintextDetached(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). Recipients(material.keyRingTestPublic). SigningKeys(material.keyRingTestPrivate). PlainDetachedSignature(). New() decHandle, _ := material.pgp.Decryption(). DecryptionKeys(material.keyRingTestPrivate). VerificationKeys(material.keyRingTestPublic). PlainDetachedSignature(). New() testEncryptSplitDecryptStream( t, []byte(testMessageString), nil, encHandle, decHandle, splitWriterDetachedSignature, len(material.keyRingTestPrivate.entities), Bytes, ) }) } } func TestPasswordEncryptDecryptPlaintextDetached(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). Password(password). SigningKeys(material.keyRingTestPrivate). PlainDetachedSignature(). New() decHandle, _ := material.pgp.Decryption(). Passwords(decPasswords). VerificationKeys(material.keyRingTestPublic). PlainDetachedSignature(). New() testEncryptSplitDecryptStream( t, []byte(testMessageString), nil, encHandle, decHandle, splitWriterDetachedSignature, len(material.keyRingTestPrivate.entities), Bytes, ) }) } } func TestSessionKeyEncryptDecryptPlaintextDetached(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). SessionKey(material.testSessionKey). SigningKeys(material.keyRingTestPrivate). PlainDetachedSignature(). New() decHandle, _ := material.pgp.Decryption(). SessionKey(material.testSessionKey). VerificationKeys(material.keyRingTestPublic). PlainDetachedSignature(). New() testEncryptSplitDecryptStream( t, []byte(testMessageString), nil, encHandle, decHandle, splitWriterDetachedSignature, len(material.keyRingTestPrivate.entities), Bytes, ) }) } } func TestPasswordEncryptDecryptStream(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). Password(password). New() decHandle, _ := material.pgp.Decryption(). Passwords(decPasswords). New() testEncryptDecryptStream( t, []byte(testMessageUTF8), nil, encHandle, decHandle, 0, Bytes, ) }) } } func TestPasswordEncryptSignDecryptStream(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). Password(password). SigningKeys(material.keyRingTestPrivate). New() decHandle, _ := material.pgp.Decryption(). Passwords(decPasswords). VerificationKeys(material.keyRingTestPublic). New() testEncryptDecryptStream( t, []byte(testMessageUTF8), nil, encHandle, decHandle, 0, Bytes, ) }) } } func TestPasswordEncryptSignDecryptStreamWithCachedSession(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). Password(password). SigningKeys(material.keyRingTestPrivate). SessionKey(material.testSessionKey). New() decHandle, _ := material.pgp.Decryption(). SessionKey(material.testSessionKey). VerificationKeys(material.keyRingTestPublic). New() testEncryptDecryptStream( t, []byte(testMessageUTF8), nil, encHandle, decHandle, 0, Bytes, ) }) } } func TestEncryptDecrypt(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). Recipients(material.keyRingTestPublic). SigningKeys(material.keyRingTestPrivate). New() decHandle, _ := material.pgp.Decryption(). DecryptionKeys(material.keyRingTestPrivate). VerificationKeys(material.keyRingTestPublic). New() testEncryptDecrypt( t, []byte(testMessage), nil, encHandle, decHandle, ) }) } } func TestEncryptDecryptUTF8(t *testing.T) { for _, material := range testMaterialForProfiles { metadata := &LiteralMetadata{ isUTF8: true, } t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). Recipients(material.keyRingTestPublic). SigningKeys(material.keyRingTestPrivate). Utf8(). New() decHandle, _ := material.pgp.Decryption(). DecryptionKeys(material.keyRingTestPrivate). VerificationKeys(material.keyRingTestPublic). New() testEncryptDecrypt( t, []byte(testMessageUTF8), metadata, encHandle, decHandle, ) }) } } func TestEncryptDecryptSessionKey(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandle, _ := material.pgp.Encryption(). Recipients(material.keyRingTestPublic). New() decHandle, _ := material.pgp.Decryption(). DecryptionKeys(material.keyRingTestPrivate). New() keyPackets, err := encHandle.EncryptSessionKey(material.testSessionKey) if err != nil { t.Fatal("Expected no error while generating key packet, got:", err) } decryptedSessionKey, err := decHandle.DecryptSessionKey(keyPackets) if err != nil { t.Fatal("Expected no error while decrypting key packet, got:", err) } if decryptedSessionKey.Algo == "" { // for v6 algorithm is not encoded in the key assert.Exactly(t, material.testSessionKey.Key, decryptedSessionKey.Key) } else { assert.Exactly(t, material.testSessionKey, decryptedSessionKey) } }) } } func TestEncryptDecryptKey(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { key := material.keyRingTestPrivate.GetKeys()[0] keyLocked, err := material.pgp.LockKey(key, password) if err != nil { t.Fatal("Expected no error while encrypting key, got:", err) } unlockedKey, err := keyLocked.Unlock(password) if err != nil { t.Fatal("Expected no error while decrypting key, got:", err) } reflect.DeepEqual(key, unlockedKey) }) } } func TestEncryptCompressionApplied(t *testing.T) { const numReplicas = 10 builder := strings.Builder{} for i := 0; i < numReplicas; i++ { builder.WriteString(testMessage) } messageToEncrypt := builder.String() for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { encHandleCompress, _ := material.pgp.Encryption(). Recipients(material.keyRingTestPublic). SigningKeys(material.keyRingTestPrivate). Compress(). New() encHandle, _ := material.pgp.Encryption(). Recipients(material.keyRingTestPublic). SigningKeys(material.keyRingTestPrivate). New() compressedMessage, err := encHandleCompress.Encrypt([]byte(messageToEncrypt)) if err != nil { t.Fatal(err) } message, err := encHandle.Encrypt([]byte(messageToEncrypt)) if err != nil { t.Fatal(err) } if len(compressedMessage.DataPacket) >= len(message.DataPacket) { t.Fatal("Expected compressed encrypted message to be smaller than the encrypted message") } }) } } func TestEncryptDecryptPlaintextDetachedArmor(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { var ciphertextBuf bytes.Buffer var detachedSignature bytes.Buffer encHandle, _ := material.pgp.Encryption(). Recipients(material.keyRingTestPublic). SigningKeys(material.keyRingTestPrivate). PlainDetachedSignature(). New() decHandle, _ := material.pgp.Decryption(). DecryptionKeys(material.keyRingTestPrivate). VerificationKeys(material.keyRingTestPublic). PlainDetachedSignature(). New() writer := NewPGPSplitWriterDetachedSignature(&ciphertextBuf, &detachedSignature) ctWriter, err := encHandle.EncryptingWriter(writer, Armor) if err != nil { t.Fatal("Expected no error while encrypting message, got:", err) } if _, err := ctWriter.Write([]byte(testMessage)); err != nil { t.Fatal(err) } if err := ctWriter.Close(); err != nil { t.Fatal(err) } decryptionResult, err := decHandle.DecryptDetached(ciphertextBuf.Bytes(), detachedSignature.Bytes(), Armor) if err != nil { t.Fatal("Expected no error while decrypting message, got:", err) } if !bytes.Equal(decryptionResult.data, []byte(testMessage)) { t.Fatalf("Expected the decrypted data to be %s got %s", string(decryptionResult.data), testMessage) } if err := decryptionResult.SignatureError(); err != nil { t.Fatal("Expected no signature error") } decHandleNotPlaintext, _ := material.pgp.Decryption(). DecryptionKeys(material.keyRingTestPrivate). VerificationKeys(material.keyRingTestPublic). New() _, err = decHandleNotPlaintext.DecryptDetached(ciphertextBuf.Bytes(), detachedSignature.Bytes(), Armor) if err == nil { t.Fatal("Expected that decrypting an non encrypted plaintext signature fails") } }) } } func TestEncryptArmor(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { isV6 := material.keyRingTestPublic.GetKeys()[0].isV6() encHandle, _ := material.pgp.Encryption(). Recipients(material.keyRingTestPublic). SigningKeys(material.keyRingTestPrivate). New() pgpMsg, err := encHandle.Encrypt([]byte(testMessageString)) if err != nil { t.Fatal("Expected no error in encryption, got:", err) } armoredData, err := pgpMsg.Armor() if err != nil { t.Fatal("Armoring failed, got:", err) } hasChecksum := containsChecksum(armoredData) if isV6 && hasChecksum { t.Fatalf("V6 messages should not have a checksum") } }) } } func containsChecksum(armored string) bool { re := regexp.MustCompile(`=([A-Za-z0-9+/]{4})\s*-----END PGP MESSAGE-----`) return re.MatchString(armored) } func testEncryptDecrypt( t *testing.T, messageBytes []byte, metadata *LiteralMetadata, encHandle PGPEncryption, decHandle PGPDecryption, ) { expectedMetadata := metadata pgpMessage, err := encHandle.Encrypt(messageBytes) if err != nil { t.Fatal("Expected no error while encrypting with key ring, got:", err) } ciphertextBytes := pgpMessage.Bytes() decryptionResult, err := decHandle.Decrypt(ciphertextBytes, Bytes) if err != nil { t.Fatal("Expected no error while calling decrypt with key ring, got:", err) } if err = decryptionResult.SignatureError(); err != nil { t.Fatal("Expected no signature verification error, got:", err) } if !bytes.Equal(decryptionResult.Bytes(), messageBytes) { t.Fatalf("Expected the decrypted data to be %s got %s", string(decryptionResult.Bytes()), string(messageBytes)) } decryptedMeta := decryptionResult.Metadata() if expectedMetadata == nil { expectedMetadata = &LiteralMetadata{ filename: metadata.Filename(), isUTF8: metadata.IsUtf8(), ModTime: metadata.Time(), } } if !reflect.DeepEqual(expectedMetadata, decryptedMeta) { t.Fatalf("Expected the decrypted metadata to be %v got %v", metadata, decryptedMeta) } } func testEncryptSplitDecryptStream( t *testing.T, messageBytes []byte, metadata *LiteralMetadata, //nolint:unparam encHandle PGPEncryption, decHandle PGPDecryption, multiWriterCreator func(Writer, Writer, Writer) PGPSplitWriter, numberOfSigsToVerify int, encoding int8, //nolint:unparam ) { messageReader := bytes.NewReader(messageBytes) var keyPackets bytes.Buffer var ciphertextBuf bytes.Buffer var detachedSignature bytes.Buffer expectedMetadata := metadata splitOutput := multiWriterCreator(&keyPackets, &ciphertextBuf, &detachedSignature) messageWriter, err := encHandle.EncryptingWriter(splitOutput, encoding) if err != nil { t.Fatal("Expected no error while encrypting stream with key ring, got:", err) } bufferSize := 2 buffer := make([]byte, bufferSize) _, err = io.CopyBuffer(messageWriter, messageReader, buffer) if err != nil { t.Fatal("Expected no error while copying data, got:", err) } err = messageWriter.Close() if err != nil { t.Fatal("Expected no error while closing plaintext writer, got:", err) } keyPacketsBytes := keyPackets.Bytes() ciphertextBytes := ciphertextBuf.Bytes() detachedSignatureBytes := detachedSignature.Bytes() pgpMessageReader := io.MultiReader( bytes.NewReader(keyPacketsBytes), bytes.NewReader(ciphertextBytes), ) if len(detachedSignatureBytes) != 0 { detachedSignatureReader := io.MultiReader( bytes.NewReader(keyPacketsBytes), bytes.NewReader(detachedSignatureBytes), ) pgpMessageReader = NewPGPSplitReader(pgpMessageReader, detachedSignatureReader) } decryptedReader, err := decHandle.DecryptingReader(pgpMessageReader, encoding) if err != nil { t.Fatal("Expected no error while calling decrypting stream with key ring, got:", err) } _, err = decryptedReader.VerifySignature() if err == nil { t.Fatal("Expected verify error not read all, got nil") } decryptedBytes, err := io.ReadAll(decryptedReader) if err != nil { t.Fatal("Expected no error while reading the decrypted data, got:", err) } if !bytes.Equal(decryptedBytes, messageBytes) { t.Fatalf("Expected the decrypted data to be %s got %s", string(decryptedBytes), string(messageBytes)) } if numberOfSigsToVerify > 0 { verifyResult, err := decryptedReader.VerifySignature() if err != nil { t.Fatal("Expected no error, got:", err) } if err = verifyResult.SignatureError(); err != nil { t.Fatal("Expected no error while verifying the signature, got:", err) } if len(verifyResult.Signatures) != numberOfSigsToVerify { t.Fatalf("Not enough signatures verified, should be %d", numberOfSigsToVerify) } for _, verifiedSignature := range verifyResult.Signatures { if verifiedSignature.SignatureError != nil { t.Fatal("One of the contained signatures did not correctly verify ", verifiedSignature.SignatureError.Message) } } } decryptedMeta := decryptedReader.GetMetadata() if expectedMetadata == nil { expectedMetadata = &LiteralMetadata{ filename: metadata.Filename(), isUTF8: metadata.IsUtf8(), ModTime: metadata.Time(), } } if !reflect.DeepEqual(expectedMetadata, decryptedMeta) { t.Fatalf("Expected the decrypted metadata to be %v got %v", metadata, decryptedMeta) } } func testEncryptDecryptStream( t *testing.T, messageBytes []byte, metadata *LiteralMetadata, encHandle PGPEncryption, decHandle PGPDecryption, numberOfSigsToVerify int, encoding int8, ) { messageReader := bytes.NewReader(messageBytes) var ciphertextBuf bytes.Buffer expectedMetadata := metadata messageWriter, err := encHandle.EncryptingWriter(&ciphertextBuf, encoding) if err != nil { t.Fatal("Expected no error while encrypting stream with key ring, got:", err) } bufferSize := 2 buffer := make([]byte, bufferSize) _, err = io.CopyBuffer(messageWriter, messageReader, buffer) if err != nil { t.Fatal("Expected no error while copying data, got:", err) } err = messageWriter.Close() if err != nil { t.Fatal("Expected no error while closing plaintext writer, got:", err) } ciphertextBytes := ciphertextBuf.Bytes() decryptedReader, err := decHandle.DecryptingReader(bytes.NewReader(ciphertextBytes), encoding) if err != nil { t.Fatal("Expected no error while calling decrypting stream with key ring, got:", err) } _, err = decryptedReader.VerifySignature() if err == nil { t.Fatal("Expected an error while verifying the signature before reading the data, got nil") } decryptedBytes, err := io.ReadAll(decryptedReader) if err != nil { t.Fatal("Expected no error while reading the decrypted data, got:", err) } if !bytes.Equal(decryptedBytes, messageBytes) { t.Fatalf("Expected the decrypted data to be %s got %s", string(decryptedBytes), string(messageBytes)) } if numberOfSigsToVerify > 0 { verifyResult, err := decryptedReader.VerifySignature() if err != nil { t.Fatal("Expected no error while verifying the signature, got:", err) } if err = verifyResult.SignatureError(); err != nil { t.Fatal("Expected no signature error while verifying the signature, got:", err) } if len(verifyResult.Signatures) != numberOfSigsToVerify { t.Fatalf("Not enough signatures verified, should be %d", numberOfSigsToVerify) } for _, verifiedSignature := range verifyResult.Signatures { if verifiedSignature.SignatureError != nil { t.Fatal("One of the contained signatures did not correctly verify ", verifiedSignature.SignatureError.Message) } } } decryptedMeta := decryptedReader.GetMetadata() if expectedMetadata == nil { expectedMetadata = &LiteralMetadata{ filename: metadata.Filename(), isUTF8: metadata.IsUtf8(), ModTime: metadata.Time(), } } if !reflect.DeepEqual(expectedMetadata, decryptedMeta) { t.Fatalf("Expected the decrypted metadata to be %v got %v", metadata, decryptedMeta) } } func splitWriter(w1 Writer, w2 Writer, w3 Writer) PGPSplitWriter { return NewPGPSplitWriterKeyAndData(w1, w2) } func splitWriterDetachedSignature(w1 Writer, w2 Writer, w3 Writer) PGPSplitWriter { return NewPGPSplitWriter(w1, w2, w3) } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/encryption.go000066400000000000000000000040561472137411600246430ustar00rootroot00000000000000package crypto import "github.com/ProtonMail/go-crypto/openpgp/packet" type EncryptionProfile interface { EncryptionConfig() *packet.Config CompressionConfig() *packet.Config } // PGPEncryption is an interface for encrypting messages with GopenPGP. // Use an EncryptionHandleBuilder to create a PGPEncryption handle. type PGPEncryption interface { // EncryptingWriter returns a wrapper around underlying output Writer, // such that any write-operation via the wrapper results in a write to an encrypted pgp message. // If the output Writer is of type PGPSplitWriter, the output can be split to multiple writers // for different parts of the message. For example to write key packets and encrypted data packets // to different writers or to write a detached signature separately. // The encoding argument defines the output encoding, i.e., Bytes or Armored // The returned pgp message WriteCloser must be closed after the plaintext has been written. EncryptingWriter(output Writer, encoding int8) (WriteCloser, error) // Encrypt encrypts a plaintext message. Encrypt(message []byte) (*PGPMessage, error) // EncryptSessionKey encrypts a session key with the encryption handle. // To encrypt a session key, the handle must contain either recipients or a password. EncryptSessionKey(sessionKey *SessionKey) ([]byte, error) // ClearPrivateParams clears all private key material contained in EncryptionHandle from memory. ClearPrivateParams() } // Writer replicates the io.Writer interface for go-mobile. type Writer interface { Write(b []byte) (n int, err error) } // WriteCloser replicates the io.WriteCloser interface for go-mobile. type WriteCloser interface { Write(b []byte) (n int, err error) Close() (err error) } // PGPSplitWriter is an interface to write different parts of a PGP message // (i.e., packets) to different streams. type PGPSplitWriter interface { Writer // Keys returns the Writer to which the key packets are written to. Keys() Writer // Signature returns the Writer to which an encrypted detached signature is written to. Signature() Writer } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/encryption_core.go000066400000000000000000000312421472137411600256500ustar00rootroot00000000000000package crypto import ( "io" "time" "github.com/ProtonMail/go-crypto/openpgp/packet" openpgp "github.com/ProtonMail/go-crypto/openpgp/v2" "github.com/ProtonMail/gopenpgp/v3/constants" "github.com/ProtonMail/gopenpgp/v3/internal" "github.com/pkg/errors" ) // pgpSplitWriter type implements the PGPSplitWriter // interface. type pgpSplitWriter struct { keyPackets Writer ciphertext Writer detachedSignature Writer } // pgpSplitWriter implements the PGPSplitWriter interface func (mw *pgpSplitWriter) Keys() Writer { return mw.keyPackets } func (mw *pgpSplitWriter) Write(b []byte) (int, error) { return mw.ciphertext.Write(b) } func (mw *pgpSplitWriter) Signature() Writer { return mw.detachedSignature } // NewPGPSplitWriter creates a type that implements the PGPSplitWriter interface // for encrypting a plaintext where the output PGP packets should be written to the different streams provided. // Key packets are written to keyPackets whereas the encrypted data packets are written to encPackets. // The encrypted detached signature data is written to encSigPacket. func NewPGPSplitWriter(keyPackets Writer, encPackets Writer, encSigPacket Writer) PGPSplitWriter { return &pgpSplitWriter{ keyPackets: keyPackets, ciphertext: encPackets, detachedSignature: encSigPacket, } } // NewPGPSplitWriterKeyAndData creates a type that implements the PGPSplitWriter interface // for encrypting a plaintext where the output PGP packets should be written to the different streams provided. // Key packets are written to keyPackets whereas the encrypted data packets are written to encPackets. func NewPGPSplitWriterKeyAndData(keyPackets Writer, encPackets Writer) PGPSplitWriter { return NewPGPSplitWriter(keyPackets, encPackets, nil) } // NewPGPSplitWriterDetachedSignature creates a type that implements the PGPSplitWriter interface // for encrypting a plaintext where the output PGP messages should be written to the different streams provided. // The encrypted data message is written to encMessage whereas the encrypted detached signature is written to // encSigMessage. func NewPGPSplitWriterDetachedSignature(encMessage Writer, encSigMessage Writer) PGPSplitWriter { return NewPGPSplitWriter(nil, encMessage, encSigMessage) } // NewPGPSplitWriterFromWriter creates a type that implements the PGPSplitWriter interface // for encrypting a plaintext where the output PGP messages to the provided Writer. func NewPGPSplitWriterFromWriter(writer Writer) PGPSplitWriter { return NewPGPSplitWriter(writer, writer, nil) } type signAndEncryptWriteCloser struct { signWriter WriteCloser encryptWriter WriteCloser } func (w *signAndEncryptWriteCloser) Write(b []byte) (int, error) { return w.signWriter.Write(b) } func (w *signAndEncryptWriteCloser) Close() error { if err := w.signWriter.Close(); err != nil { return err } return w.encryptWriter.Close() } func (eh *encryptionHandle) prepareEncryptAndSign( plainMessageMetadata *LiteralMetadata, ) (hints *openpgp.FileHints, config *packet.Config, signEntities []*openpgp.Entity, err error) { hints = &openpgp.FileHints{ FileName: plainMessageMetadata.Filename(), IsUTF8: eh.IsUTF8, ModTime: time.Unix(plainMessageMetadata.Time(), 0), } config = eh.profile.EncryptionConfig() config.Time = eh.clock compressionConfig := eh.selectCompression() config.DefaultCompressionAlgo = compressionConfig.DefaultCompressionAlgo config.CompressionConfig = compressionConfig.CompressionConfig if eh.SigningContext != nil { config.SignatureNotations = append(config.SignatureNotations, eh.SigningContext.getNotation()) } if eh.SignKeyRing != nil && len(eh.SignKeyRing.entities) > 0 { signEntities, err = eh.SignKeyRing.signingEntities() if err != nil { return } } return } func (eh *encryptionHandle) encryptStream( keyPacketWriter Writer, dataPacketWriter Writer, plainMessageMetadata *LiteralMetadata, ) (plainMessageWriter WriteCloser, err error) { var sessionKeyBytes []byte var additionalPasswords [][]byte if eh.SessionKey != nil { sessionKeyBytes = eh.SessionKey.Key } if eh.Password != nil { additionalPasswords = [][]byte{eh.Password} } hints, config, signers, err := eh.prepareEncryptAndSign(plainMessageMetadata) if err != nil { return nil, err } var encryptionTimeOverride *time.Time if eh.encryptionTimeOverride != nil { encryptionTime := eh.encryptionTimeOverride() encryptionTimeOverride = &encryptionTime } plainMessageWriter, err = openpgp.EncryptWithParams( dataPacketWriter, eh.Recipients.getEntities(), eh.HiddenRecipients.getEntities(), &openpgp.EncryptParams{ KeyWriter: keyPacketWriter, Signers: signers, Hints: hints, SessionKey: sessionKeyBytes, Passwords: additionalPasswords, Config: config, TextSig: eh.IsUTF8, OutsideSig: eh.ExternalSignature, EncryptionTime: encryptionTimeOverride, }, ) if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in encrypting asymmetrically") } return plainMessageWriter, nil } func (eh *encryptionHandle) encryptStreamWithPassword( keyPacketWriter Writer, dataPacketWriter Writer, plainMessageMetadata *LiteralMetadata, ) (plainMessageWriter io.WriteCloser, err error) { var sessionKeyBytes []byte if eh.SessionKey != nil { sessionKeyBytes = eh.SessionKey.Key } hints, config, signers, err := eh.prepareEncryptAndSign(plainMessageMetadata) if err != nil { return } plainMessageWriter, err = openpgp.SymmetricallyEncryptWithParams( eh.Password, dataPacketWriter, &openpgp.EncryptParams{ KeyWriter: keyPacketWriter, Signers: signers, Hints: hints, SessionKey: sessionKeyBytes, Config: config, TextSig: eh.IsUTF8, OutsideSig: eh.ExternalSignature, }, ) if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in encrypting asymmetrically") } return plainMessageWriter, nil } func (eh *encryptionHandle) encryptStreamWithSessionKey( dataPacketWriter Writer, plainMessageMetadata *LiteralMetadata, ) (plainMessageWriter WriteCloser, err error) { encryptWriter, signWriter, err := eh.encryptStreamWithSessionKeyHelper( plainMessageMetadata, dataPacketWriter, ) if err != nil { return nil, err } if signWriter != nil { plainMessageWriter = &signAndEncryptWriteCloser{signWriter, encryptWriter} } else { plainMessageWriter = encryptWriter } return plainMessageWriter, err } func (eh *encryptionHandle) encryptStreamWithSessionKeyHelper( plainMessageMetadata *LiteralMetadata, dataPacketWriter io.Writer, ) (encryptWriter, signWriter io.WriteCloser, err error) { hints, config, signers, err := eh.prepareEncryptAndSign(plainMessageMetadata) if err != nil { return nil, nil, err } if !eh.SessionKey.v6 { config.DefaultCipher, err = eh.SessionKey.GetCipherFunc() if err != nil { return nil, nil, errors.Wrap(err, "gopenpgp: unable to encrypt with session key") } } encryptWriter, err = packet.SerializeSymmetricallyEncrypted( dataPacketWriter, config.Cipher(), config.AEAD() != nil, packet.CipherSuite{Cipher: config.Cipher(), Mode: config.AEAD().Mode()}, eh.SessionKey.Key, config, ) if err != nil { return nil, nil, errors.Wrap(err, "gopenpgp: unable to encrypt") } if algo := config.Compression(); algo != packet.CompressionNone { encryptWriter, err = packet.SerializeCompressed(encryptWriter, algo, config.CompressionConfig) if err != nil { return nil, nil, errors.Wrap(err, "gopenpgp: error in compression") } } if signers != nil { signWriter, err = openpgp.SignWithParams(encryptWriter, signers, &openpgp.SignParams{ Hints: hints, TextSig: eh.IsUTF8, OutsideSig: eh.ExternalSignature, Config: config, }) if err != nil { return nil, nil, errors.Wrap(err, "gopenpgp: unable to sign") } } else { encryptWriter, err = packet.SerializeLiteral( encryptWriter, !plainMessageMetadata.IsUtf8(), plainMessageMetadata.Filename(), uint32(plainMessageMetadata.Time()), ) if err != nil { return nil, nil, errors.Wrap(err, "gopenpgp: unable to serialize") } } return encryptWriter, signWriter, nil } type encryptSignDetachedWriter struct { ptToCiphertextWriter WriteCloser sigToCiphertextWriter WriteCloser ptToEncSigWriter WriteCloser ptWriter Writer } func (w *encryptSignDetachedWriter) Write(b []byte) (int, error) { return w.ptWriter.Write(b) } func (w *encryptSignDetachedWriter) Close() error { if err := w.ptToCiphertextWriter.Close(); err != nil { return err } if err := w.ptToEncSigWriter.Close(); err != nil { return err } return w.sigToCiphertextWriter.Close() } // encryptSignDetachedStreamWithSessionKey wraps writers to encrypt a message // with a session key and produces a detached signature for the plaintext. func (eh *encryptionHandle) encryptSignDetachedStreamWithSessionKey( plainMessageMetadata *LiteralMetadata, encryptedSignatureWriter io.Writer, encryptedDataWriter io.Writer, encryptSignature bool, ) (io.WriteCloser, error) { signKeyRing := eh.SignKeyRing eh.SignKeyRing = nil defer func() { eh.SignKeyRing = signKeyRing }() // Create a writer to encrypt the message. ptToCiphertextWriter, err := eh.encryptStreamWithSessionKey(encryptedDataWriter, plainMessageMetadata) if err != nil { return nil, err } var sigToCiphertextWriter io.WriteCloser if encryptSignature { // Create a writer to encrypt the signature. sigToCiphertextWriter, err = eh.encryptStreamWithSessionKey(encryptedSignatureWriter, nil) if err != nil { return nil, err } } else { // The signature is not encrypted sigToCiphertextWriter = internal.NewNoOpWriteCloser(encryptedSignatureWriter) } // Create a writer to sign the message. ptToEncSigWriter, err := signMessageDetachedWriter( signKeyRing, sigToCiphertextWriter, eh.IsUTF8, eh.SigningContext, eh.clock, eh.profile.EncryptionConfig(), ) if err != nil { return nil, err } // Return a wrapped plaintext writer that writes encrypted data and the encrypted signature. return &encryptSignDetachedWriter{ ptToCiphertextWriter: ptToCiphertextWriter, sigToCiphertextWriter: sigToCiphertextWriter, ptToEncSigWriter: ptToEncSigWriter, ptWriter: io.MultiWriter(ptToCiphertextWriter, ptToEncSigWriter), }, nil } func (eh *encryptionHandle) encryptSignDetachedStreamToRecipients( plainMessageMetadata *LiteralMetadata, encryptedSignatureWriter io.Writer, encryptedDataWriter io.Writer, keyPacketWriter io.Writer, encryptSignature bool, ) (plaintextWriter io.WriteCloser, err error) { configInput := eh.profile.EncryptionConfig() configInput.Time = NewConstantClock(eh.clock().Unix()) // Generate a session key for encryption. if eh.SessionKey == nil { eh.SessionKey, err = generateSessionKey(configInput) if err != nil { return nil, err } defer func() { eh.SessionKey.Clear() eh.SessionKey = nil }() } if keyPacketWriter == nil { // If no separate keyPacketWriter is given, write the key packets // as prefix to the encrypted data and encrypted signature. keyPacketWriter = io.MultiWriter(encryptedDataWriter, encryptedSignatureWriter) } encryptionTimeOverride := configInput.Now() if eh.encryptionTimeOverride != nil { encryptionTimeOverride = eh.encryptionTimeOverride() } if eh.Recipients != nil || eh.HiddenRecipients != nil { // Encrypt the session key to the different recipients. if err = encryptSessionKeyToWriter( eh.Recipients, eh.HiddenRecipients, eh.SessionKey, keyPacketWriter, encryptionTimeOverride, configInput, ); err != nil { return nil, err } } if eh.Password != nil { // If not recipients present use the provided password if err = encryptSessionKeyWithPasswordToWriter( eh.Password, eh.SessionKey, keyPacketWriter, configInput, ); err != nil { return nil, err } } if eh.Password == nil && eh.Recipients == nil && eh.HiddenRecipients == nil { return nil, errors.New("openpgp: no key material to encrypt") } // Use the session key to encrypt message + signature of the message. plaintextWriter, err = eh.encryptSignDetachedStreamWithSessionKey( plainMessageMetadata, encryptedSignatureWriter, encryptedDataWriter, encryptSignature, ) if err != nil { return nil, err } return plaintextWriter, err } func (eh *encryptionHandle) selectCompression() (config *packet.Config) { config = &packet.Config{} switch eh.Compression { case constants.DefaultCompression: config = eh.profile.CompressionConfig() case constants.ZIPCompression: config.DefaultCompressionAlgo = packet.CompressionZIP config.CompressionConfig = &packet.CompressionConfig{ Level: 6, } case constants.ZLIBCompression: config.DefaultCompressionAlgo = packet.CompressionZLIB config.CompressionConfig = &packet.CompressionConfig{ Level: 6, } } return config } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/encryption_handle.go000066400000000000000000000301421472137411600261510ustar00rootroot00000000000000package crypto import ( "io" "github.com/ProtonMail/go-crypto/openpgp/armor" openpgp "github.com/ProtonMail/go-crypto/openpgp/v2" "github.com/ProtonMail/gopenpgp/v3/constants" "github.com/ProtonMail/gopenpgp/v3/internal" "github.com/pkg/errors" ) // encryptionHandle collects the configuration parameters for encrypting a message. // Use a encryptionHandleBuilder to create a handle. type encryptionHandle struct { // Recipients contains the public keys to which // the message should be encrypted to. // Triggers hybrid encryption with public keys of the recipients and hidden recipients. // The recipients are included in the intended recipient fingerprint list // of the signature, if a signature is present. // If nil, set another field for the type of encryption: HiddenRecipients, SessionKey, or Password Recipients *KeyRing // HiddenRecipients contains the public keys to which // the message should be encrypted to. // Triggers hybrid encryption with public keys of the recipients and hidden recipients. // The hidden recipients are NOT included in the intended recipient fingerprint list // of the signature, if a signature is present. // If nil, set another field for the type of encryption: Recipients, SessionKey, or Password HiddenRecipients *KeyRing // SessionKey defines the session key the message should be encrypted with. // Triggers session key encryption with the included session key. // If nil, set another field for the type of encryption: Recipients, HiddenRecipients, or Password SessionKey *SessionKey // Password defines a password the message should be encrypted with. // Triggers password based encryption with a key derived from the password. // If nil, set another field for the type of encryption: Recipients, HiddenRecipients, or SessionKey Password []byte // SignKeyRing provides an unlocked key ring to include signature in the message. // If nil, no signature is included. SignKeyRing *KeyRing // SigningContext provides a signing context for the signature in the message. // SignKeyRing has to be set if a SigningContext is provided. SigningContext *SigningContext // ArmorHeaders provides armor headers if the message is armored. // Only considered if Armored is set to true. ArmorHeaders map[string]string // Compression indicates if the plaintext should be compressed before encryption. // constants.NoCompression: none, constants.DefaultCompression: profile default // constants.ZIPCompression: zip, constants.ZLIBCompression: zlib Compression int8 // DetachedSignature indicates if a separate encrypted detached signature // should be created DetachedSignature bool // PlainDetachedSignature indicates that the detached signature should not be encrypted. // Is only considered if DetachedSignature is not set. PlainDetachedSignature bool IsUTF8 bool // ExternalSignature allows to include an external signature into // the encrypted message. ExternalSignature []byte profile EncryptionProfile encryptionTimeOverride Clock clock Clock } // --- Default decryption handle to build from func defaultEncryptionHandle(profile EncryptionProfile, clock Clock) *encryptionHandle { return &encryptionHandle{ profile: profile, clock: clock, } } // --- Implements PGPEncryption interface // EncryptingWriter returns a wrapper around underlying output Writer, // such that any write-operation via the wrapper results in a write to an encrypted pgp message. // If the output Writer is of type PGPSplitWriter, the output can be split to multiple writers // for different parts of the message. For example to write key packets and encrypted data packets // to different writers or to write a detached signature separately. // The encoding argument defines the output encoding, i.e., Bytes or Armored // The returned pgp message WriteCloser must be closed after the plaintext has been written. func (eh *encryptionHandle) EncryptingWriter(outputWriter Writer, encoding int8) (messageWriter WriteCloser, err error) { pgpSplitWriter := castToPGPSplitWriter(outputWriter) if pgpSplitWriter != nil { return eh.encryptingWriters(pgpSplitWriter.Keys(), pgpSplitWriter, pgpSplitWriter.Signature(), nil, armorOutput(encoding)) } if eh.DetachedSignature { return nil, errors.New("gopenpgp: no pgp split writer provided for the detached signature") } return eh.encryptingWriters(nil, outputWriter, nil, nil, armorOutput(encoding)) } // Encrypt encrypts a plaintext message. func (eh *encryptionHandle) Encrypt(message []byte) (*PGPMessage, error) { pgpMessageBuffer := NewPGPMessageBuffer() // Enforce that for a PGPMessage struct the output should not be armored. encryptingWriter, err := eh.EncryptingWriter(pgpMessageBuffer, Bytes) if err != nil { return nil, err } _, err = encryptingWriter.Write(message) if err != nil { return nil, err } err = encryptingWriter.Close() if err != nil { return nil, err } checksum := eh.armorChecksumRequired() return pgpMessageBuffer.PGPMessageWithOptions(eh.PlainDetachedSignature, !checksum), nil } // EncryptSessionKey encrypts a session key with the encryption handle. // To encrypt a session key, the handle must contain either recipients or a password. func (eh *encryptionHandle) EncryptSessionKey(sessionKey *SessionKey) ([]byte, error) { config := eh.profile.EncryptionConfig() config.Time = NewConstantClock(eh.clock().Unix()) switch { case eh.Password != nil: return encryptSessionKeyWithPassword(sessionKey, eh.Password, config) case eh.Recipients != nil || eh.HiddenRecipients != nil: encryptionTimeOverride := config.Now() if eh.encryptionTimeOverride != nil { encryptionTimeOverride = eh.encryptionTimeOverride() } return encryptSessionKey(eh.Recipients, eh.HiddenRecipients, sessionKey, encryptionTimeOverride, config) } return nil, errors.New("gopenpgp: no password or recipients in encryption handle") } // --- Helper methods on encryption handle func (eh *encryptionHandle) validate() error { if eh.Recipients == nil && eh.HiddenRecipients == nil && eh.Password == nil && eh.SessionKey == nil { return errors.New("gopenpgp: no encryption key material provided") } if eh.SignKeyRing == nil && eh.SigningContext != nil { return errors.New("gopenpgp: no signing key but signing context provided") } if eh.SignKeyRing == nil && eh.DetachedSignature { return errors.New("gopenpgp: no signing key provided for detached signature") } return nil } // armorChecksumRequired determines if an armor checksum should be appended or not. // The OpenPGP Crypto-Refresh mandates that no checksum should be appended with the new packets. func (eh *encryptionHandle) armorChecksumRequired() bool { if !constants.ArmorChecksumEnabled { // If the default behavior is no checksum, we can ignore // the logic for the RFC9580 check. return false } encryptionConfig := eh.profile.EncryptionConfig() if encryptionConfig.AEADConfig == nil { return true } checkTime := eh.clock() if eh.Recipients != nil { for _, recipient := range eh.Recipients.entities { primarySelfSignature, err := recipient.PrimarySelfSignature(checkTime, encryptionConfig) if err != nil { return true } if !primarySelfSignature.SEIPDv2 { return true } } } if eh.HiddenRecipients != nil { for _, recipient := range eh.HiddenRecipients.entities { primarySelfSignature, err := recipient.PrimarySelfSignature(checkTime, encryptionConfig) if err != nil { return true } if !primarySelfSignature.SEIPDv2 { return true } } } return false } type armoredWriteCloser struct { armorWriter WriteCloser messageWriter WriteCloser armorSigWriter WriteCloser } func (w *armoredWriteCloser) Write(b []byte) (int, error) { return w.messageWriter.Write(b) } func (w *armoredWriteCloser) Close() error { if err := w.messageWriter.Close(); err != nil { return err } if w.armorSigWriter != nil { if err := w.armorSigWriter.Close(); err != nil { return err } } return w.armorWriter.Close() } // ClearPrivateParams clears all private key material contained in EncryptionHandle from memory. func (eh *encryptionHandle) ClearPrivateParams() { if eh.SignKeyRing != nil { eh.SignKeyRing.ClearPrivateParams() } if eh.SessionKey != nil { eh.SessionKey.Clear() } if eh.Password != nil { clearMem(eh.Password) } } func (eh *encryptionHandle) handleArmor(keys, data, detachedSignature Writer) ( dataOut Writer, detachedSignatureOut Writer, armorWriter WriteCloser, armorSigWriter WriteCloser, err error, ) { writeChecksum := eh.armorChecksumRequired() detachedSignatureOut = detachedSignature // Wrap armored writer if eh.ArmorHeaders == nil { eh.ArmorHeaders = internal.ArmorHeaders } armorWriter, err = armor.EncodeWithChecksumOption(data, constants.PGPMessageHeader, eh.ArmorHeaders, writeChecksum) dataOut = armorWriter if err != nil { return nil, nil, nil, nil, err } if eh.DetachedSignature { armorSigWriter, err = armor.EncodeWithChecksumOption(detachedSignature, constants.PGPMessageHeader, eh.ArmorHeaders, writeChecksum) detachedSignatureOut = armorSigWriter if err != nil { return nil, nil, nil, nil, err } } else if eh.PlainDetachedSignature { armorSigWriter, err = armor.EncodeWithChecksumOption(detachedSignature, constants.PGPSignatureHeader, eh.ArmorHeaders, writeChecksum) detachedSignatureOut = armorSigWriter if err != nil { return nil, nil, nil, nil, err } } if keys != nil { return nil, nil, nil, nil, errors.New("gopenpgp: armor is not allowed if key packets are written separately") } return dataOut, detachedSignatureOut, armorWriter, armorSigWriter, nil } func (eh *encryptionHandle) encryptingWriters(keys, data, detachedSignature Writer, meta *LiteralMetadata, armorOutput bool) (messageWriter WriteCloser, err error) { var armorWriter WriteCloser var armorSigWriter WriteCloser if err = eh.validate(); err != nil { return nil, err } doDetachedSignature := eh.DetachedSignature || eh.PlainDetachedSignature if doDetachedSignature && detachedSignature == nil { return nil, errors.New("gopenpgp: no output provided for the detached signature") } if armorOutput { data, detachedSignature, armorWriter, armorSigWriter, err = eh.handleArmor(keys, data, detachedSignature) if err != nil { return nil, err } } if keys == nil { // No writer for key packets provided, // write the key packets at the beginning of each message. if eh.DetachedSignature { keys = io.MultiWriter(data, detachedSignature) } else { keys = data } } switch { case eh.Recipients.CountEntities() > 0 || eh.HiddenRecipients.CountEntities() > 0: // Encrypt towards recipients if !doDetachedSignature { // Signature is inside the ciphertext. messageWriter, err = eh.encryptStream(keys, data, meta) } else { // Encrypted detached signature separate from the ciphertext. messageWriter, err = eh.encryptSignDetachedStreamToRecipients(meta, detachedSignature, data, keys, eh.DetachedSignature) } case eh.Password != nil: // Encrypt with a password if !doDetachedSignature { messageWriter, err = eh.encryptStreamWithPassword(keys, data, meta) } else { messageWriter, err = eh.encryptSignDetachedStreamToRecipients(meta, detachedSignature, data, keys, eh.DetachedSignature) } case eh.SessionKey != nil: // Encrypt towards session key if !doDetachedSignature { messageWriter, err = eh.encryptStreamWithSessionKey(data, meta) } else { messageWriter, err = eh.encryptSignDetachedStreamWithSessionKey(meta, detachedSignature, data, eh.DetachedSignature) } default: // No encryption material provided err = errors.New("gopenpgp: no encryption key ring, session key, or password provided") } if err != nil { return nil, err } if armorOutput { // Wrap armored writer messageWriter = &armoredWriteCloser{ armorWriter: armorWriter, messageWriter: messageWriter, armorSigWriter: armorSigWriter, } } if eh.IsUTF8 { messageWriter = internal.NewUtf8CheckWriteCloser( openpgp.NewCanonicalTextWriteCloser(messageWriter), ) } return messageWriter, nil } func castToPGPSplitWriter(w Writer) PGPSplitWriter { v, ok := interface{}(w).(PGPSplitWriter) if ok { return v } v, ok = interface{}(&w).(PGPSplitWriter) if ok { return v } return nil } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/encryption_handle_builder.go000066400000000000000000000214751472137411600276700ustar00rootroot00000000000000package crypto import "github.com/ProtonMail/gopenpgp/v3/constants" // EncryptionHandleBuilder allows to configure a decryption handle to decrypt an OpenPGP message. type EncryptionHandleBuilder struct { handle *encryptionHandle defaultClock Clock err error } func newEncryptionHandleBuilder(profile EncryptionProfile, clock Clock) *EncryptionHandleBuilder { return &EncryptionHandleBuilder{ handle: defaultEncryptionHandle(profile, clock), defaultClock: clock, } } // Recipient sets the public key to which the message should be encrypted to. // Triggers hybrid encryption with public keys of the recipients and hidden recipients. // The recipients are included in the intended recipient fingerprint list // of the signature, if a signature is present. // If not set, set another type of encryption: HiddenRecipients, SessionKey, or Password. func (ehb *EncryptionHandleBuilder) Recipient(key *Key) *EncryptionHandleBuilder { var err error if ehb.handle.Recipients == nil { ehb.handle.Recipients, err = NewKeyRing(key) } else { err = ehb.handle.Recipients.AddKey(key) } ehb.err = err return ehb } // Recipients sets the public keys to which the message should be encrypted to. // Triggers hybrid encryption with public keys of the recipients and hidden recipients. // The recipients are included in the intended recipient fingerprint list // of the signature, if a signature is present. // If not set, set another type of encryption: HiddenRecipients, SessionKey, or Password. func (ehb *EncryptionHandleBuilder) Recipients(recipients *KeyRing) *EncryptionHandleBuilder { ehb.handle.Recipients = recipients return ehb } // HiddenRecipient sets a public key to which the message should be encrypted to. // Triggers hybrid encryption with public keys of the recipients and hidden recipients. // The hidden recipients are NOT included in the intended recipient fingerprint list // of the signature, if a signature is present. // If not set, set another type of encryption: Recipients, SessionKey, or Password. func (ehb *EncryptionHandleBuilder) HiddenRecipient(key *Key) *EncryptionHandleBuilder { var err error if ehb.handle.HiddenRecipients == nil { ehb.handle.HiddenRecipients, err = NewKeyRing(key) } else { err = ehb.handle.HiddenRecipients.AddKey(key) } ehb.err = err return ehb } // HiddenRecipients sets the public keys to which the message should be encrypted to. // Triggers hybrid encryption with public keys of the recipients and hidden recipients. // The hidden recipients are NOT included in the intended recipient fingerprint list // of the signature, if a signature is present. // If not set, set another type of encryption: Recipients, SessionKey, or Password. func (ehb *EncryptionHandleBuilder) HiddenRecipients(hiddenRecipients *KeyRing) *EncryptionHandleBuilder { ehb.handle.HiddenRecipients = hiddenRecipients return ehb } // SigningKey sets the signing key that are used to create signature of the message. // Triggers that signatures are created for each signing key. // If not set, no signature is included. func (ehb *EncryptionHandleBuilder) SigningKey(key *Key) *EncryptionHandleBuilder { var err error if ehb.handle.SignKeyRing == nil { ehb.handle.SignKeyRing, err = NewKeyRing(key) } else { err = ehb.handle.SignKeyRing.AddKey(key) } ehb.err = err return ehb } // SigningKeys sets the signing keys that are used to create signature of the message. // Triggers that signatures are created for each signing key. // If not set, no signature is included. func (ehb *EncryptionHandleBuilder) SigningKeys(signingKeys *KeyRing) *EncryptionHandleBuilder { ehb.handle.SignKeyRing = signingKeys return ehb } // SigningContext provides a signing context for the signature in the message. // Triggers that each signature includes the sining context. // SigningKeys have to be set if a SigningContext is provided. func (ehb *EncryptionHandleBuilder) SigningContext(siningContext *SigningContext) *EncryptionHandleBuilder { ehb.handle.SigningContext = siningContext return ehb } // SessionKey sets the session key the message should be encrypted with. // Triggers session key encryption with the included session key. // If not set, set another the type of encryption: Recipients, HiddenRecipients, or Password. func (ehb *EncryptionHandleBuilder) SessionKey(sessionKey *SessionKey) *EncryptionHandleBuilder { ehb.handle.SessionKey = sessionKey return ehb } // Password sets a password the message should be encrypted with. // Triggers password based encryption with a key derived from the password. // If not set, set another the type of encryption: Recipients, HiddenRecipients, or SessionKey. func (ehb *EncryptionHandleBuilder) Password(password []byte) *EncryptionHandleBuilder { ehb.handle.Password = password return ehb } // Compress indicates if the plaintext should be compressed before encryption. // Compression affects security and opens the door for side-channel attacks, which // might allow to extract the plaintext data without a decryption key. // RFC9580 recommends to not use compression. func (ehb *EncryptionHandleBuilder) Compress() *EncryptionHandleBuilder { ehb.handle.Compression = constants.DefaultCompression return ehb } // CompressWith indicates if the plaintext should be compressed before encryption. // Compression affects security and opens the door for side-channel attacks, which // might allow to extract the plaintext data without a decryption key. // RFC9580 recommends to not use compression. // Allowed config options: // constants.NoCompression: none, constants.DefaultCompression: profile default // constants.ZIPCompression: zip, constants.ZLIBCompression: zlib. func (ehb *EncryptionHandleBuilder) CompressWith(config int8) *EncryptionHandleBuilder { switch config { case constants.NoCompression, constants.DefaultCompression, constants.ZIPCompression, constants.ZLIBCompression: ehb.handle.Compression = config } return ehb } // Utf8 indicates if the plaintext should be signed with a text type // signature. If set, the plaintext is signed after canonicalising the line endings. func (ehb *EncryptionHandleBuilder) Utf8() *EncryptionHandleBuilder { ehb.handle.IsUTF8 = true return ehb } // DetachedSignature indicates that the message should be signed, // but the signature should not be included in the same pgp message as the input data. // Instead the detached signature is encrypted in a separate pgp message. func (ehb *EncryptionHandleBuilder) DetachedSignature() *EncryptionHandleBuilder { ehb.handle.DetachedSignature = true return ehb } // PlainDetachedSignature indicates that the message should be signed, // but the signature should not be included in the same pgp message as the input data. // Instead the detached signature is a separate signature pgp message. // If DetachedSignature signature is set (i.e., the detached signature is encrypted), this option is ignored. // NOTE: A plaintext detached signature might reveal information about the encrypted plaintext. Thus, use with care. func (ehb *EncryptionHandleBuilder) PlainDetachedSignature() *EncryptionHandleBuilder { ehb.handle.PlainDetachedSignature = true return ehb } // IncludeExternalSignature indicates that the provided signature should be included // in the produced encrypted message. // Special feature: should not be used in normal use-cases, // can lead to broken or invalid PGP messages. func (ehb *EncryptionHandleBuilder) IncludeExternalSignature(signature []byte) *EncryptionHandleBuilder { ehb.handle.ExternalSignature = signature return ehb } // EncryptionTime allows to specify a separate time for selecting encryption keys // instead of the internal clock (also used for signing). Note that the internal clock can be changed with SignTime. // If the input unixTime is 0 no expiration checks are performed on the encryption keys. func (ehb *EncryptionHandleBuilder) EncryptionTime(unixTime int64) *EncryptionHandleBuilder { if unixTime == 0 { ehb.handle.encryptionTimeOverride = ZeroClock() } else { ehb.handle.encryptionTimeOverride = NewConstantClock(unixTime) } return ehb } // SignTime sets the internal clock to always return // the supplied unix time for signing instead of the system time. func (ehb *EncryptionHandleBuilder) SignTime(unixTime int64) *EncryptionHandleBuilder { ehb.handle.clock = NewConstantClock(unixTime) return ehb } // New creates an EncryptionHandle and checks that the given // combination of parameters is valid. If the parameters are invalid // an error is returned. func (ehb *EncryptionHandleBuilder) New() (PGPEncryption, error) { if ehb.err != nil { return nil, ehb.err } ehb.err = ehb.handle.validate() if ehb.err != nil { return nil, ehb.err } params := ehb.handle ehb.handle = defaultEncryptionHandle(ehb.handle.profile, ehb.defaultClock) return params, nil } // Error returns an errors that occurred within the builder. func (ehb *EncryptionHandleBuilder) Error() error { return ehb.err } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/encryption_session.go000066400000000000000000000141161472137411600264040ustar00rootroot00000000000000package crypto import ( "bytes" "io" "strconv" "time" "github.com/ProtonMail/go-crypto/openpgp/packet" "github.com/pkg/errors" ) // decryptSessionKey returns the decrypted session key from one or multiple binary encrypted session key packets. func decryptSessionKey(keyRing *KeyRing, keyPacket []byte) (*SessionKey, error) { var p packet.Packet var ek *packet.EncryptedKey var err error var hasPacket = false var decryptErr error keyReader := bytes.NewReader(keyPacket) packets := packet.NewReader(keyReader) Loop: for { if p, err = packets.Next(); err != nil { break } switch p := p.(type) { case *packet.EncryptedKey: hasPacket = true ek = p unverifiedEntities := keyRing.entities.EntitiesById(p.KeyId) for _, unverifiedEntity := range unverifiedEntities { keys := unverifiedEntity.DecryptionKeys(p.KeyId, time.Time{}, &packet.Config{}) for _, key := range keys { priv := key.PrivateKey if priv.Encrypted { continue } if decryptErr = ek.Decrypt(priv, nil); decryptErr == nil { break Loop } } } case *packet.SymmetricallyEncrypted, *packet.AEADEncrypted, *packet.Compressed, *packet.LiteralData: break Loop default: continue Loop } } if !hasPacket { if err != nil { return nil, errors.Wrap(err, "gopenpgp: couldn't find a session key packet") } else { return nil, errors.New("gopenpgp: couldn't find a session key packet") } } if decryptErr != nil { return nil, errors.Wrap(decryptErr, "gopenpgp: error in decrypting") } if ek == nil || ek.Key == nil { return nil, errors.New("gopenpgp: unable to decrypt session key: no valid decryption key") } return newSessionKeyFromEncrypted(ek) } // encryptSessionKey encrypts the session key with the unarmored // publicKey and returns a binary public-key encrypted session key packet. func encryptSessionKey( recipients *KeyRing, hiddenRecipients *KeyRing, sk *SessionKey, date time.Time, config *packet.Config) ([]byte, error) { outbuf := &bytes.Buffer{} err := encryptSessionKeyToWriter(recipients, hiddenRecipients, sk, outbuf, date, config) if err != nil { return nil, err } return outbuf.Bytes(), nil } // EncryptSessionKeyToWriter encrypts the session key with the unarmored // publicKey and returns a binary public-key encrypted session key packet. func encryptSessionKeyToWriter( recipients *KeyRing, hiddenRecipients *KeyRing, sk *SessionKey, outputWriter io.Writer, date time.Time, config *packet.Config, ) (err error) { var cf packet.CipherFunction if sk.v6 { cf = config.Cipher() } else { cf, err = sk.GetCipherFunc() } if err != nil { return errors.Wrap(err, "gopenpgp: unable to encrypt session key") } pubKeys := make([]*packet.PublicKey, 0, len(recipients.getEntities())+len(hiddenRecipients.getEntities())) aeadSupport := config.AEAD() != nil for _, e := range append(recipients.getEntities(), hiddenRecipients.getEntities()...) { encryptionKey, ok := e.EncryptionKey(date, config) if !ok { return errors.New("gopenpgp: encryption key is unavailable for key id " + strconv.FormatUint(e.PrimaryKey.KeyId, 16)) } primarySelfSignature, _ := e.PrimarySelfSignature(date, config) if primarySelfSignature == nil { return errors.Wrap(err, "gopenpgp: entity without a self-signature") } if !primarySelfSignature.SEIPDv2 { aeadSupport = false } pubKeys = append(pubKeys, encryptionKey.PublicKey) } if len(pubKeys) == 0 { return errors.New("gopenpgp: cannot set key: no public key available") } for index, pub := range pubKeys { isHidden := index >= len(recipients.getEntities()) err := packet.SerializeEncryptedKeyAEADwithHiddenOption(outputWriter, pub, cf, aeadSupport, sk.Key, isHidden, nil) if err != nil { return errors.Wrap(err, "gopenpgp: cannot set key") } } return nil } // decryptSessionKeyWithPassword decrypts the binary symmetrically encrypted // session key packet and returns the session key. func decryptSessionKeyWithPassword(keyPacket, password []byte) (*SessionKey, error) { keyReader := bytes.NewReader(keyPacket) packets := packet.NewReader(keyReader) var symKeys []*packet.SymmetricKeyEncrypted for { var p packet.Packet var err error if p, err = packets.Next(); err != nil { break } if p, ok := p.(*packet.SymmetricKeyEncrypted); ok { symKeys = append(symKeys, p) } } // Try the symmetric passphrase first if len(symKeys) != 0 && password != nil { for _, s := range symKeys { key, cipherFunc, err := s.Decrypt(password) if err == nil { sk := &SessionKey{ Key: key, Algo: getAlgo(cipherFunc), v6: cipherFunc == 0, // for v6 there is not algorithm specified } if err = sk.checkSize(); !sk.v6 && err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to decrypt session key with password") } return sk, nil } } } return nil, errors.New("gopenpgp: unable to decrypt any packet") } // encryptSessionKeyWithPassword encrypts the session key with the password and // returns a binary symmetrically encrypted session key packet. func encryptSessionKeyWithPassword(sk *SessionKey, password []byte, config *packet.Config) (encrypted []byte, err error) { outbuf := &bytes.Buffer{} err = encryptSessionKeyWithPasswordToWriter(password, sk, outbuf, config) if err != nil { return nil, err } return outbuf.Bytes(), nil } func encryptSessionKeyWithPasswordToWriter(password []byte, sk *SessionKey, outputWriter io.Writer, config *packet.Config) (err error) { var cf packet.CipherFunction if sk.v6 { cf = config.Cipher() } else { cf, err = sk.GetCipherFunc() } if err != nil { return errors.Wrap(err, "gopenpgp: unable to encrypt session key with password") } if len(password) == 0 { return errors.New("gopenpgp: password can't be empty") } if err = sk.checkSize(); !sk.v6 && err != nil { return errors.Wrap(err, "gopenpgp: unable to encrypt session key with password") } config.DefaultCipher = cf err = packet.SerializeSymmetricKeyEncryptedReuseKey(outputWriter, sk.Key, password, config) if err != nil { return errors.Wrap(err, "gopenpgp: unable to encrypt session key with password") } return nil } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/interop_test.go000066400000000000000000000712121472137411600251660ustar00rootroot00000000000000package crypto import ( "bytes" "testing" "github.com/ProtonMail/gopenpgp/v3/internal" ) func TestDetachedSignaturesWithUnknownPackets(t *testing.T) { const ricarda_key_armor = `-----BEGIN PGP PUBLIC KEY BLOCK----- Comment: 2ADE 0F8A A059 6BC9 4E50 D2AD 9162 53AB 652E F195 xsDNBGJvrDABDACrZUY7VU1uZ/uzntlAKEHVF4mb3eYSdW1rE3hVke0HoDvtQbzq KQ9qgfPaNwdkxRexgrNGSeKkQJcgR7gMWxFxM/FwddQIXfVL43nRlN+iGvFDYR+9 dn5gSOD9EvZUYLN9p6yR3Umyglt4NpdjYM0J+Rn2DVyfGHCtS+z1fdym1h1zdImo rArBpWMEdvNN/6dR8BN67WSBs5pVsvnDPdjbeU+GPJVoRH4CWe/LdJnJDICPmlva gAyeJeK+KitkxD8IIc9d18x5dV1Z/LL2o1B0Psort8+az2Z+NbkP2cUv0DDRyZIM Ww1A6KMSSNuvewXGCU+gEFlGIA83zfq7XE3WNp9EPy9xCs610+KxSS9cftKdrMmU cl37Gb1lZyLFIBUCwPdIyTvhs6r6rMgu4GQ46sPl8qeLbtaoXnPWj9V1Fn9RoMgz Kq8ZItFCJfCbf+gamx/0S/0mE47giuAtymw8Hf53e3jsSANK28GpcsEUNqWT4djb YgcWl2iXR7n0i9cAEQEAAcLBSQQfAQoAfQWCYm+sMAMLCQcJEJFiU6tlLvGVRxQA AAAAAB4AIHNhbHRAbm90YXRpb25zLnNlcXVvaWEtcGdwLm9yZ6O6vv9v4H1aAR9Z aEksrL/2rQGm4Omv2SCubCC1pk/DAxUKCAKbAQIeARYhBCreD4qgWWvJTlDSrZFi U6tlLvGVAACp1wv+MEkIs8x2Wk6e+i4rbclnkBjR2tSwv3N66jcz09QeDt5xwX1Q jq1TP+XGFJfFA+LUugbLWNzWqwh7CypSc6IAB82+Ha+lCMjY3SZLfTe6crUgDWOZ wDprVND6z2g9UlgJ6rfFf329LEUziknjKFBbreONH12tOzvCxrxipp84J0DZEqO3 0VB2b2B7uO1X5V1aQMFj4JEafQ6Or6uXtR3Fwcs/JALwhqydy3LI4Y0s/y91qdPP 69DgugVDbG/Kkp5W2CNtGyd51cnEoFEbh9nV0hHR+rERU2ZcyoNfZQCyPuHMIT1L PndcWLsT6Ga3TvXLUEhOOl6CPpox0aV7bsGpip0u54yGkhgR5YYLchcTVt15q5+/ M5Z03et1LcSZKk1ijSFXNsOWdD2ojneN3vhlKbJoDosT10WyCsXKL8JNP4F4q4nU 22+/N1sttbgzSatwPxyiC7kKymQmDtg8NCyyCtpDoRkEIzaMv+4DqoMVkvLRcF1K vX+rNEg1OxneqMSEzS1SaWNhcmRhIFMuIMOBbHZhcmV6IDxyaWNhcmRhQG9wZW5w Z3AuZXhhbXBsZT7CwUwEEwEKAIAFgmJvrDADCwkHCRCRYlOrZS7xlUcUAAAAAAAe ACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmfo22n7d9n+Nv3PxzMP93f7 rejDV4BFsobH6T5cZGvj8AMVCggCmQECmwECHgEWIQQq3g+KoFlryU5Q0q2RYlOr ZS7xlQAAu6EL/iJ91h1dwcQMZpbKYnBbH/1U/ncbIlhkQf8YzjrpzVprU0sr4cKu mx42EylcteODVoDN8ITGROUC8Prw5tu+NS2mjkKWUlj56eLkpS3A3D6NqPIFEzU3 KYztp+Y0hq2ZmsGsPgL1AbVPc2+ngUSL4pXgQ5hmVoD3B6VGqBReyKXhZNzH42S5 fMuOsY8+/xgQ0WDwSCVeUW7Otql24iFji9U4eL036AzOO1hXkbOesrw4E7GmU2mR kkX/aDZ9bGYT3yVZ/CJkU4wrUHJWW1IJl/bl//becL8Vnqr92vQkYQnUh19zIi2n 6ualROjcoITjjRemvkBfM9zXTd6kVFKD+ySDnGtNq62Ukz0/COg81tAnnnXeNhlP 1M8yA6zfrY17tAFYLmALUrPYjVy4ZJuaHScnIcM5lHIKYn1ijetGQSjI4sT/mSi4 8fwNHFRufR7ta9XWv5b4+m8SAyrJ/FqnRoOwtoph0ZxSItjpv+qLPX2N4M8/JOqh 3QhI5ZDd+ScGJc7AzQRib6wwAQwArMv2IdO1f8a/brBc/+LeCqyqR+qLKzZRLAvF +c6+qG7D9OzZCJfbPltnQ5BgRzIiSKgzDugDDt0m3fdWBxOQG5Ojo53Xu1ZTgRUD 0KWI4kH5Cs0gp3Kl62TdNAxNUlHdWqJ6G6WYVMlMhLmBVPjo65pT1+OON2v/O/qA 8ZJRlK3RyKym4Kcr8JbtX1roSRtVPRpi++Y1CGuhnK3UM68putqfgZOnTZxln2m2 BUrL8fWgme2rTJyrrN8fSM61dZZ+5E0SWDMBxEp5bimMrRjJc7V0JMUx2HiCDe/l panzleAugfEVUeAYsEe9C+7k3p2r00roL0dWnrMgfhGnJy5ccmPyzEQpoA6ARq1a EBk2Syr/QNO93GfDFcK9pTcDcQdUgq93x5s9LShLQ7fuvVXXxkl4QkdKJn+Vb2yP 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 =i+jK -----END PGP PUBLIC KEY BLOCK----- ` const sig = `-----BEGIN PGP SIGNATURE----- wsE7BAABCgBvBYJkit2rCRD7/MgqAV5zMEcUAAAAAAAeACBzYWx0QG5vdGF0aW9u cy5zZXF1b2lhLXBncC5vcmelgsnbOPsc1mt9YRUNBmoAWxgPfqyzTjfUu2WQ1NQd MhYhBNGmbhojsYLJmA94jPv8yCoBXnMwAAC0TAv8CsSeavcLIjJvUKBMV+I09fmA D/HCf9ZtV7Y+JPOaOMBgWnNaoVINRenDbQLz69Yq8Xf8zyOOdX1GUpiO/0vdHnw2 TdJc6tkWB2yP63DfwGQD5xxSzltfvO1GV7BUYVIUXZqATp39wp7nmn6BJ15DtlLT mUwwQ0eDfwtAGcyZBfDkz1V7p+AYuWWDCTRXk0LVl8mjsXheX1BX4uzlru6LWE88 JL1uNDcRfvg1WDBCV0zTQwWlmmsWF42KCft6p/c+ak5XstzEKalnDtASoU/o07bF QXVr2ncHexfjyyZRo9ZH0s4jn71J83Djou4O6O9zgo19kL1aErEDC3J9n041qvvV xi5ZVvmVVeTrGrJ71UyoMCRxyFu+vtBnvoRluLcw5NxKgniASJCRtXvUYYxG048I 9m6pSkC41QlEc+4r325i/Ny4p6VLwZDK+APN1MQRd85MHjKpGNAiVHYLtdAzdABr VpAFLmdML2VLIiCG9R6Zw8U2Hww5DSy5Gq0UM1tJwsE7BAABCgBvBYJkit2rCRCz +fFdlxFkrkcUAAAAAAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmdI 0DufwhTqCzYcRYQp4VAE+Qxp2Ruj+srVlIBkA20qZRYhBN9WS6uCrGY2n74Fz7P5 8V2XEWSuAADSCwwAhfAVzNHeLEgrXHJAgrpP31ubBebEVmOl3jUPg4+cko2LJBGE egeONp4kVrxMmk9AKURfQ4UaVFXh6Cyhjq5zFZQJnZ2fmHJm/L1A7r+XUwTQ2dZy LGVSZCPNbKEuJxcZzYO9fDtbJIoY5OeIBFmasvbGle4laotKhleMopfqzJLuZJIa zxDAsJbdcm/sVbHLeElK4cjcEtiZZKNizzZnTE827WlZVll1FZ+a3Gi8SQXV+asy aRVUb1hw1VzFj3ZmtcRIPctEy5uYZq8Oaa0U8Z+J10ertSGh/2I1Au7G7SXiYVzB 65LXj4daJ3JZTCjpqc82AJdnpVpREPpCfaopUchA+NYNaIaolx/SmgkeLxyWXff+ 5GHfuVDQpD8Ma7hOx6aP+Ih/xI8OrMgx9sZ79L9mdbcSCaypqYd/oez1pwrfvcN8 c6rmTo+LPGN1CKceOyPdcKEZBnwY/QrNf3GDgZSnm69Iol16OvqstTrFU26z1WT6 sWC04HotaaBXdIHf =nNOz -----END PGP SIGNATURE-----` message := "Hello World :)" key, err := NewKeyFromArmored(ricarda_key_armor) if err != nil { t.Error("error: ", err) } pgp := PGP() verifier, err := pgp.Verify().VerificationKey(key).New() if err != nil { t.Error("error: ", err) } res, err := verifier.VerifyDetached([]byte(message), []byte(sig), Armor) if err != nil { t.Error("error: ", err) } if err = res.SignatureError(); err != nil { t.Error("Should have no signature error, got:", err) } } func TestSignedAndEncryptedMessages(t *testing.T) { const bob_key_armor = `-----BEGIN PGP PRIVATE KEY BLOCK----- Comment: Bob's OpenPGP Transferable Secret Key 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 =miES -----END PGP PRIVATE KEY BLOCK----- ` msg := `-----BEGIN PGP MESSAGE----- Comment: Plaintext is "Hello\r\nWorld!\n" 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 Ik4fzHKnqkcmTwUng+v5sDcU2R2x4Rel6YuR =knHG -----END PGP MESSAGE----- ` expected := "Hello\r\nWorld!\n" key, err := NewKeyFromArmored(bob_key_armor) if err != nil { t.Error("error: ", err) } pgp := PGP() decryptor, err := pgp.Decryption().DecryptionKey(key).VerificationKey(key).New() if err != nil { t.Error("error: ", err) } res, err := decryptor.Decrypt([]byte(msg), Armor) if err != nil { t.Error("error: ", err) } if err = res.SignatureError(); err != nil { t.Error("Should have no signature error, got:", err) } if !bytes.Equal(res.Bytes(), []byte(expected)) { t.Errorf("Should be equal, got: %s", res.Bytes()) } } func TestProblematicCleartextSignature(t *testing.T) { const bob_key_armor = `-----BEGIN PGP PRIVATE KEY BLOCK----- Comment: Bob's OpenPGP Transferable Secret Key lQVYBF2lnPIBDAC5cL9PQoQLTMuhjbYvb4Ncuuo0bfmgPRFywX53jPhoFf4Zg6mv /seOXpgecTdOcVttfzC8ycIKrt3aQTiwOG/ctaR4Bk/t6ayNFfdUNxHWk4WCKzdz /56fW2O0F23qIRd8UUJp5IIlN4RDdRCtdhVQIAuzvp2oVy/LaS2kxQoKvph/5pQ/ 5whqsyroEWDJoSV0yOb25B/iwk/pLUFoyhDG9bj0kIzDxrEqW+7Ba8nocQlecMF3 X5KMN5kp2zraLv9dlBBpWW43XktjcCZgMy20SouraVma8Je/ECwUWYUiAZxLIlMv 9CurEOtxUw6N3RdOtLmYZS9uEnn5y1UkF88o8Nku890uk6BrewFzJyLAx5wRZ4F0 qV/yq36UWQ0JB/AUGhHVPdFf6pl6eaxBwT5GXvbBUibtf8YI2og5RsgTWtXfU7eb SGXrl5ZMpbA6mbfhd0R8aPxWfmDWiIOhBufhMCvUHh1sApMKVZnvIff9/0Dca3wb vLIwa3T4CyshfT0AEQEAAQAL/RZqbJW2IqQDCnJi4Ozm++gPqBPiX1RhTWSjwxfM cJKUZfzLj414rMKm6Jh1cwwGY9jekROhB9WmwaaKT8HtcIgrZNAlYzANGRCM4TLK 3VskxfSwKKna8l+s+mZglqbAjUg3wmFuf9Tj2xcUZYmyRm1DEmcN2ZzpvRtHgX7z Wn1mAKUlSDJZSQks0zjuMNbupcpyJokdlkUg2+wBznBOTKzgMxVNC9b2g5/tMPUs hGGWmF1UH+7AHMTaS6dlmr2ZBIyogdnfUqdNg5sZwsxSNrbglKP4sqe7X61uEAIQ bD7rT3LonLbhkrj3I8wilUD8usIwt5IecoHhd9HziqZjRCc1BUBkboUEoyedbDV4 i4qfsFZ6CEWoLuD5pW7dEp0M+WeuHXO164Rc+LnH6i1VQrpb1Okl4qO6ejIpIjBI 1t3GshtUu/mwGBBxs60KBX5g77mFQ9lLCRj8lSYqOsHRKBhUp4qM869VA+fD0BRP fqPT0I9IH4Oa/A3jYJcg622GwQYA1LhnP208Waf6PkQSJ6kyr8ymY1yVh9VBE/g6 fRDYA+pkqKnw9wfH2Qho3ysAA+OmVOX8Hldg+Pc0Zs0e5pCavb0En8iFLvTA0Q2E LR5rLue9uD7aFuKFU/VdcddY9Ww/vo4k5p/tVGp7F8RYCFn9rSjIWbfvvZi1q5Tx +akoZbga+4qQ4WYzB/obdX6SCmi6BndcQ1QdjCCQU6gpYx0MddVERbIp9+2SXDyL hpxjSyz+RGsZi/9UAshT4txP4+MZBgDfK3ZqtW+h2/eMRxkANqOJpxSjMyLO/FXN WxzTDYeWtHNYiAlOwlQZEPOydZFty9IVzzNFQCIUCGjQ/nNyhw7adSgUk3+BXEx/ MyJPYY0BYuhLxLYcrfQ9nrhaVKxRJj25SVHj2ASsiwGJRZW4CC3uw40OYxfKEvNC mer/VxM3kg8qqGf9KUzJ1dVdAvjyx2Hz6jY2qWCyRQ6IMjWHyd43C4r3jxooYKUC YnstRQyb/gCSKahveSEjo07CiXMr88UGALwzEr3npFAsPW3osGaFLj49y1oRe11E he9gCHFm+fuzbXrWmdPjYU5/ZdqdojzDqfu4ThfnipknpVUM1o6MQqkjM896FHm8 zbKVFSMhEP6DPHSCexMFrrSgN03PdwHTO6iBaIBBFqmGY01tmJ03SxvSpiBPON9P NVvy/6UZFedTq8A07OUAxO62YUSNtT5pmK2vzs3SAZJmbFbMh+NN204TRI72GlqT t5hcfkuv8hrmwPS/ZR6q312mKQ6w/1pqO9qitCFCb2IgQmFiYmFnZSA8Ym9iQG9w ZW5wZ3AuZXhhbXBsZT6JAc4EEwEKADgCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgEC F4AWIQTRpm4aI7GCyZgPeIz7/MgqAV5zMAUCXaWe+gAKCRD7/MgqAV5zMG9sC/9U 2T3RrqEbw533FPNfEflhEVRIZ8gDXKM8hU6cqqEzCmzZT6xYTe6sv4y+PJBGXJFX yhj0g6FDkSyboM5litOcTupURObVqMgA/Y4UKERznm4fzzH9qek85c4ljtLyNufe doL2pp3vkGtn7eD0QFRaLLmnxPKQ/TlZKdLE1G3u8Uot8QHicaR6GnAdc5UXQJE3 BiV7jZuDyWmZ1cUNwJkKL6oRtp+ZNDOQCrLNLecKHcgCqrpjSQG5oouba1I1Q6Vl sP44dhA1nkmLHtxlTOzpeHj4jnk1FaXmyasurrrI5CgU/L2Oi39DGKTH/A/cywDN 4ZplIQ9zR8enkbXquUZvFDe+Xz+6xRXtb5MwQyWODB3nHw85HocLwRoIN9WdQEI+ L8a/56AuOwhs8llkSuiITjR7r9SgKJC2WlAHl7E8lhJ3VDW3ELC56KH308d6mwOG ZRAqIAKzM1T5FGjMBhq7ZV0eqdEntBh3EcOIfj2M8rg1MzJv+0mHZOIjByawikad BVgEXaWc8gEMANYwv1xsYyunXYK0X1vY/rP1NNPvhLyLIE7NpK90YNBj+xS1ldGD bUdZqZeef2xJe8gMQg05DoD1DF3GipZ0Ies65beh+d5hegb7N4pzh0LzrBrVNHar 29b5ExdI7i4iYD5TO6Vr/qTUOiAN/byqELEzAb+L+b2DVz/RoCm4PIp1DU9ewcc2 WB38Ofqut3nLYA5tqJ9XvAiEQme+qAVcM3ZFcaMt4I4dXhDZZNg+D9LiTWcxdUPB leu8iwDRjAgyAhPzpFp+nWoqWA81uIiULWD1Fj+IVoY3ZvgivoYOiEFBJ9lbb4te g9m5UT/AaVDTWuHzbspVlbiVe+qyB77C2daWzNyx6UYBPLOo4r0t0c91kbNE5lgj Z7xz6los0N1U8vq91EFSeQJoSQ62XWavYmlCLmdNT6BNfgh4icLsT7Vr1QMX9jzn JtTPxdXytSdHvpSpULsqJ016l0dtmONcK3z9mj5N5z0k1tg1AH970TGYOe2aUcSx IRDMXDOPyzEfjwARAQABAAv9F2CwsjS+Sjh1M1vegJbZjei4gF1HHpEM0K0PSXsp SfVvpR4AoSJ4He6CXSMWg0ot8XKtDuZoV9jnJaES5UL9pMAD7JwIOqZm/DYVJM5h OASCh1c356/wSbFbzRHPtUdZO9Q30WFNJM5pHbCJPjtNoRmRGkf71RxtvHBzy7np Ga+W6U/NVKHw0i0CYwMI0YlKDakYW3Pm+QL+gHZFvngGweTod0f9l2VLLAmeQR/c +EZs7lNumhuZ8mXcwhUc9JQIhOkpO+wreDysEFkAcsKbkQP3UDUsA1gFx9pbMzT0 tr1oZq2a4QBtxShHzP/ph7KLpN+6qtjks3xB/yjTgaGmtrwM8tSe0wD1RwXS+/1o BHpXTnQ7TfeOGUAu4KCoOQLv6ELpKWbRBLWuiPwMdbGpvVFALO8+kvKAg9/r+/ny zM2GQHY+J3Jh5JxPiJnHfXNZjIKLbFbIPdSKNyJBuazXW8xIa//mEHMI5OcvsZBK clAIp7LXzjEjKXIwHwDcTn9pBgDpdOKTHOtJ3JUKx0rWVsDH6wq6iKV/FTVSY5jl zN+puOEsskF1Lfxn9JsJihAVO3yNsp6RvkKtyNlFazaCVKtDAmkjoh60XNxcNRqr gCnwdpbgdHP6v/hvZY54ZaJjz6L2e8unNEkYLxDt8cmAyGPgH2XgL7giHIp9jrsQ aS381gnYwNX6wE1aEikgtY91nqJjwPlibF9avSyYQoMtEqM/1UjTjB2KdD/MitK5 fP0VpvuXpNYZedmyq4UOMwdkiNMGAOrfmOeT0olgLrTMT5H97Cn3Yxbk13uXHNu/ ZUZZNe8s+QtuLfUlKAJtLEUutN33TlWQY522FV0m17S+b80xJib3yZVJteVurrh5 HSWHAM+zghQAvCesg5CLXa2dNMkTCmZKgCBvfDLZuZbjFwnwCI6u/NhOY9egKuUf SA/je/RXaT8m5VxLYMxwqQXKApzD87fv0tLPlVIEvjEsaf992tFEFSNPcG1l/jpd 5AVXw6kKuf85UkJtYR1x2MkQDrqY1QX/XMw00kt8y9kMZUre19aCArcmor+hDhRJ E3Gt4QJrD9z/bICESw4b4z2DbgD/Xz9IXsA/r9cKiM1h5QMtXvuhyfVeM01enhxM GbOH3gjqqGNKysx0UODGEwr6AV9hAd8RWXMchJLaExK9J5SRawSg671ObAU24SdY vMQ9Z4kAQ2+1ReUZzf3ogSMRZtMT+d18gT6L90/y+APZIaoArLPhebIAGq39HLmJ 26x3z0WAgrpA1kNsjXEXkoiZGPLKIGoe3hqJAbYEGAEKACAWIQTRpm4aI7GCyZgP eIz7/MgqAV5zMAUCXaWc8gIbDAAKCRD7/MgqAV5zMOn/C/9ugt+HZIwX308zI+QX c5vDLReuzmJ3ieE0DMO/uNSC+K1XEioSIZP91HeZJ2kbT9nn9fuReuoff0T0Dief rbwcIQQHFFkrqSp1K3VWmUGp2JrUsXFVdjy/fkBIjTd7c5boWljv/6wAsSfiv2V0 JSM8EFU6TYXxswGjFVfc6X97tJNeIrXL+mpSmPPqy2bztcCCHkWS5lNLWQw+R7Vg 71Fe6yBSNVrqC2/imYG2J9zlowjx1XU63Wdgqp2Wxt0l8OmsB/W80S1fRF5G4SDH s9HXglXXqPsBRZJYfP+VStm9L5P/sKjCcX6WtZR7yS6G8zj/X767MLK/djANvpPd NVniEke6hM3CNBXYPAMhQBMWhCulcoz+0lxi8L34rMN+Dsbma96psdUrn7uLaB91 6we0CTfF8qqm7BsVAgalon/UUiuMY80U3ueoj3okiSTiHIjD/YtpXSPioC8nMng7 xqAY9Bwizt4FWgXuLm1a4+So4V9j1TRCXd12Uc2l2RNmgDE= =miES -----END PGP PRIVATE KEY BLOCK----- ` const message = `From the grocery store we need: - tofu - vegetables - noodles ` key, err := NewKeyFromArmored(bob_key_armor) if err != nil { t.Error("error: ", err) } pgp := PGP() signer, err := pgp.Sign().SigningKey(key).New() if err != nil { t.Error("error: ", err) } msg, err := signer.SignCleartext([]byte(message)) if err != nil { t.Error("error: ", err) } verifier, err := pgp.Verify().VerificationKey(key).New() if err != nil { t.Error("error: ", err) } res, err := verifier.VerifyCleartext(msg) if err != nil { t.Error("error: ", err) } if err = res.SignatureError(); err != nil { t.Error("Should have no signature error, got:", err) } if !bytes.Equal(res.Cleartext(), []byte(message)) { t.Errorf("Should be equal, got: %s", res.Cleartext()) } } func TestDetachedSignaturesLowRSABits(t *testing.T) { const ricarda_key_armor = `-----BEGIN PGP PRIVATE KEY BLOCK----- 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 KNs/Xw4PLUnp6wQO2d/6oZay =ffeX -----END PGP PRIVATE KEY BLOCK----- ` const sig = `-----BEGIN PGP SIGNATURE----- wsE7BAABCgBvBYJkpnJFCRB8L6pN+Tw3skcUAAAAAAAeACBzYWx0QG5vdGF0aW9u cy5zZXF1b2lhLXBncC5vcme7t8QmfP04d0zI8u8HUPmZcNbExpgA23j+/ICq8B3N EhYhBB3c4V8JIXzuLzs3YHwvqk35PDeyAAA9fwwAtaSuGkMxdU3CyO1n8x7mBaZS F2QNzvUKlhei1vPf5RaXTlNmlDWl/wF7aqRlrbdSHnqvi5lbhVVNP5LU62tS1J1N WudlfoVhIexYOtoYOvOnsR3nBT95Mevk64UTVPs2rAfNDSD/0TKtK/gL+B9UBI2K 8UJwxcjtO116qwsO6gJq5XJjn0y34nNdIJH8Rr5I1jtl6h3Xlh2et58Yp9LmubNw mrqvl+ES8bh8Q++KpesnswQnSZR9e4lp6FY6w7X6UDyxtJF9S0SBZnsduJtsoxUl U8J1SUKwl0ATk9a+4+bwkwK9UJXFzwqEJvLoMe4U5QJKYazosr7Mxw197/iYOLXD LlSSmcS1v5Oo37CVG+cZZnyiB1vra7x1fnpR+EA/bbsKkXXQjAepMhb61IFq44dL j/6t75dByS9g29r2Fen+KFHh4QZrai9jEabepP9nKgNza7hIEeZtVdNyJfENUfQd l6qOAQGHaxD0whADX2J53HqPUpcbidzw3jEKwWgI =+Dhj -----END PGP SIGNATURE----- ` message := "Hello World :)" key, err := NewKeyFromArmored(ricarda_key_armor) if err != nil { t.Error("error: ", err) } pgp := PGP() verifier, err := pgp.Verify().VerificationKey(key).New() if err != nil { t.Error("error: ", err) } res, err := verifier.VerifyDetached([]byte(message), []byte(sig), Armor) if err != nil { t.Error("error: ", err) } if err = res.SignatureError(); err == nil { t.Error("Should have signature error", err) } } func TestDetachedSignaturesAndroid(t *testing.T) { const ricarda_key_armor = `-----BEGIN PGP PUBLIC KEY BLOCK----- Version: GopenPGP 2.1.1 Comment: https://gopenpgp.org xsBNBF1BfxUBCADUpiiG3AhQK08E2nBmQ50XeztOWArmknINQV41pqGFW5VQkfbQ 3FYsANhLGqbDBQ0XxmocjKL7W7W8Y4xmHCGgkCUy6gAqGbi+sXY9Sl8xqQNHuZDh WVdqT8+Rtv+DRxp/XrGkzC1U8CBYUmmKS92ldy0/zZIvgQXT6t5Q+v+BeUSv4jCs nY3BE0UBOljtrTXlOcXRZHQxORWG+kon0qgcJERdwwzhxY6eT8jEfAfJY0hzQaYg +6bj6ZR0zkMtY2Psq2M05kzEw4On/dezZETAu1e9fSqfk1mp+H6BeLJ9RUyrFK/P qIO48+pU8CmAvTdx5eIihyOM16CFg/3GgV85ABEBAAHNMWFkYW10c3RAcHJvdG9u bWFpbC5ibHVlIDxhZGFtdHN0QHByb3Rvbm1haWwuYmx1ZT7CwGgEEwEIABwFAl1B fxUJEBHDHo5eB/TQAhsDAhkBAgsJAhUIAADHoggACDYDZkyTMZX69k9uoAygAQ75 2kb52r0L3dSLge+hUelxJOiVUznbavzVhzjzF2FucXP0csOSJygHNejjS62BDtsX iIoPiVDO1+Hr72X4gE277VeZ1b6VozJvKC0+H4fhg/EtkD07oVhHJRxOOVlgUXGK nP2lz2ojny0McggvN+Nk8ILqt6ImlvEk6CnTs9XdmcmosMiQU+U+THKrKZ+5Yec8 4kzlHG8ee7Tim2yn9n/FuBStrYkTJUsDuAL/LOfF9DnzTzukK6kqpDB6kDfMeYQJ Lq+Tu642n74P0lqOO0Wy7imI/hxM1W8yqcNdafS7PCuGHD99mecdKWVeYHCCY87A TQRdQX8VAQgAyAIj6ytLB1CUinP6f6aVKlLSM9e9Figv1CAw53NHeQBbmwzU5bZn tE6UERnvJy6ul7hJr9Jop+O1/jA6zaGanF5wv0nEvTHcoYRpJ4QiJgiQxvhOdItH 29+jBV1F44xOzlGnEzFAv7GbPecKHAsQgX9qYCj+5ydcttQ29gWQ6nN23G03R3Lb KRS9H2uw1SIYGgif8FgKpJemwJjuSibyViXTf3JC8ZUtYbq+vIXqATFFtbrUHfKM AKlHo0uLYGq1rRINGR6Dmhu6bGhZonuW0na4+5Wh86kg9c/YI7jSIIspRRkH+v7+ RXH51h8Rbc2Tiv64qy7cIJIH0Bk0lFAaIQARAQABwsBfBBgBCAATBQJdQX8VCRAR wx6OXgf00AIbDAAAgvAIAGyLaHYTjiXG/ORIIAgdQhKBYOozrOS4EcOPNdMSPBwT 6P+BpNS/GD33pzANVKM9Mft8+NnePUFOR2f4QJrQ1VvSj9ko8P2sX7IAe7+rG614 LQfzjG5R16KlSVOMFW0K2L8ZxumDdYl/N0BhgtZmB1lg1xY2TPHoDetznMnHG8sL 6u6vyhGl5a6qcW2g1urlF0VF/CEqg1lwAKhFHIFiNR+X6jCjg0KJa9MjAW6oICOx oX0jp195mWix6suRJSWVK14uieT6uL5yYC5tZMz+t9rs7YxCkHxFRT1H5ZLHUD/r 93liqW+pzUx+bVdz5qNMb0ZonHZRLe3/Fzb19x8UMPc= =6gp8 -----END PGP PUBLIC KEY BLOCK----- ` const sig = `-----BEGIN PGP SIGNATURE----- Version: GopenPGP 2.4.10 Comment: https://gopenpgp.org wsBzBAABCgAnBQJjocOZCZARwx6OXgf00BYhBCDPNjtY7JnnIuU+xBHDHo5eB/TQ AACGgwf7Bx6J7JLZ2G6RFvr/wtl0DENZxUVS4H3wZPEIuVTh3/Lzd5BHfWN/mD+q Sz0BcjRNxAI+nDY2/J8HPIibNg1NDlUgrgxK0NPLS1DMWmtoW3JTF5sfFMyiVGxo RH4oluOe/UQcfxYTbMr8/EX8Gc9kdx4U7MqQNEc9CM5VIuxrfMpSZ2hvn5zlwexQ WdnWjVWePpbwpltX98wTlAtU93XARUgeIMrzkhEBc1sNSg6/ynECLENm8EMxWQmj 9lpaROb2Fw50G7S1YjSUlc7WK+e4+IIP3Fqw/b21Kd1BasHS92OuHZNalbxyJA0F V6Zkmvzj3h9CucLSJw1Bo6ZJTDbkBQ== =fVs7 -----END PGP SIGNATURE----- ` message := "This is a test\nWith trailing spaces: \n With leading spaces\nWith trailing tabs:\t\t\n\tWith leading tabs\nWith trailing carriage returns:\r\n\rWith leading carriage returns\n\t \r With a mix \t\r\n" message = internal.TrimEachLine(message) key, err := NewKeyFromArmored(ricarda_key_armor) if err != nil { t.Error("error: ", err) } pgp := PGP() verifier, err := pgp.Verify().VerificationKey(key).Utf8().New() if err != nil { t.Error("error: ", err) } res, err := verifier.VerifyDetached([]byte(message), []byte(sig), Armor) if err != nil { t.Error("error: ", err) } if err = res.SignatureError(); err != nil { t.Error("Should have signature error", err) } } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/key.go000066400000000000000000000332631472137411600232430ustar00rootroot00000000000000package crypto import ( "bytes" "crypto/sha256" "encoding/hex" "encoding/json" "fmt" "io" "strconv" "strings" "time" packet "github.com/ProtonMail/go-crypto/openpgp/packet" openpgp "github.com/ProtonMail/go-crypto/openpgp/v2" "github.com/ProtonMail/gopenpgp/v3/armor" "github.com/ProtonMail/gopenpgp/v3/constants" "github.com/pkg/errors" ) // Key contains a single private or public key. type Key struct { // PGP entities in this keyring. entity *openpgp.Entity } type KeyEncryptionProfile interface { KeyEncryptionConfig() *packet.Config } // --- Create Key object // NewKeyFromReader reads binary or armored data into a Key object. func NewKeyFromReader(r io.Reader) (key *Key, err error) { return NewKeyFromReaderExplicit(r, Auto) } // NewKeyFromReaderExplicit reads binary or armored data into a Key object. // Allows to set the encoding explicitly to avoid the armor check. func NewKeyFromReaderExplicit(r io.Reader, encoding int8) (key *Key, err error) { var armored bool key = &Key{} switch encoding { case Auto: r, armored = armor.IsPGPArmored(r) case Armor: armored = true case Bytes: armored = false default: return nil, errors.New("gopenpgp: encoding is not supported") } err = key.readFrom(r, armored) if err != nil { return nil, err } return key, nil } // NewKey creates a new key from the first key in the unarmored or armored binary data. // Clones the binKeys data for go-mobile compatibility. func NewKey(binKeys []byte) (key *Key, err error) { return NewKeyFromReader(bytes.NewReader(clone(binKeys))) } // NewKeyWithCloneFlag creates a new key from the first key in the unarmored or armored binary data. func NewKeyWithCloneFlag(binKeys []byte, clone bool) (key *Key, err error) { if clone { return NewKey(binKeys) } return NewKeyFromReader(bytes.NewReader(binKeys)) } // NewKeyFromArmored creates a new key from the first key in an armored string. func NewKeyFromArmored(armored string) (key *Key, err error) { return NewKeyFromReader(strings.NewReader(armored)) } // NewPrivateKeyFromArmored creates a new secret key from the first key in an armored string // and unlocks it with the password. func NewPrivateKeyFromArmored(armored string, password []byte) (key *Key, err error) { lockedKey, err := NewKeyFromArmored(armored) if err != nil { return } isLocked, err := lockedKey.IsLocked() if err != nil { return } if isLocked { key, err = lockedKey.Unlock(password) if err != nil { return nil, err } } else { key = lockedKey } return } // NewKeyFromEntity creates a key from the provided go-crypto/openpgp entity. func NewKeyFromEntity(entity *openpgp.Entity) (*Key, error) { if entity == nil { return nil, errors.New("gopenpgp: nil entity provided") } return &Key{entity: entity}, nil } // generateKey generates a key with the given key-generation profile and security-level. func generateKey(name, email string, clock Clock, profile KeyGenerationProfile, securityLevel int8, lifeTimeSec uint32) (*Key, error) { config := profile.KeyGenerationConfig(securityLevel) config.Time = NewConstantClock(clock().Unix()) config.KeyLifetimeSecs = lifeTimeSec return generateKeyWithConfig(name, email, "", config) } // --- Operate on key // Copy creates a deep copy of the key. func (key *Key) Copy() (*Key, error) { serialized, err := key.Serialize() if err != nil { return nil, err } return NewKey(serialized) } // lock locks a copy of the key. func (key *Key) lock(passphrase []byte, profile KeyEncryptionProfile) (*Key, error) { unlocked, err := key.IsUnlocked() if err != nil { return nil, err } if !unlocked { return nil, errors.New("gopenpgp: key is not unlocked") } lockedKey, err := key.Copy() if err != nil { return nil, err } if passphrase == nil { return lockedKey, nil } err = lockedKey.entity.EncryptPrivateKeys(passphrase, profile.KeyEncryptionConfig()) if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in locking key") } locked, err := lockedKey.IsLocked() if err != nil { return nil, err } if !locked { return nil, errors.New("gopenpgp: unable to lock key") } return lockedKey, nil } // Unlock unlocks a copy of the key. func (key *Key) Unlock(passphrase []byte) (*Key, error) { isLocked, err := key.IsLocked() if err != nil { return nil, err } if !isLocked { if passphrase == nil { return key.Copy() } return nil, errors.New("gopenpgp: key is not locked") } unlockedKey, err := key.Copy() if err != nil { return nil, err } err = unlockedKey.entity.DecryptPrivateKeys(passphrase) if err != nil { return nil, errors.New("gopenpgp: error in unlocking key") } isUnlocked, err := unlockedKey.IsUnlocked() if err != nil { return nil, err } if !isUnlocked { return nil, errors.New("gopenpgp: unable to unlock key") } return unlockedKey, nil } // --- Export key func (key *Key) Serialize() ([]byte, error) { var buffer bytes.Buffer var err error if key.entity.PrivateKey == nil { err = key.entity.Serialize(&buffer) } else { err = key.entity.SerializePrivateWithoutSigning(&buffer, nil) } if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in serializing key") } return buffer.Bytes(), nil } // Armor returns the armored key as a string with default gopenpgp headers. func (key *Key) Armor() (string, error) { serialized, err := key.Serialize() if err != nil { return "", err } if key.IsPrivate() { return armor.ArmorWithTypeChecksum(serialized, constants.PrivateKeyHeader, !key.isV6()) } return armor.ArmorWithTypeChecksum(serialized, constants.PublicKeyHeader, !key.isV6()) } // ArmorWithCustomHeaders returns the armored key as a string, with // the given headers. Empty parameters are omitted from the headers. func (key *Key) ArmorWithCustomHeaders(comment, version string) (string, error) { serialized, err := key.Serialize() if err != nil { return "", err } return armor.ArmorWithTypeAndCustomHeadersChecksum(serialized, constants.PrivateKeyHeader, version, comment, !key.isV6()) } // GetArmoredPublicKey returns the armored public keys from this keyring. func (key *Key) GetArmoredPublicKey() (s string, err error) { serialized, err := key.GetPublicKey() if err != nil { return "", err } return armor.ArmorWithTypeChecksum(serialized, constants.PublicKeyHeader, !key.isV6()) } // GetArmoredPublicKeyWithCustomHeaders returns the armored public key as a string, with // the given headers. Empty parameters are omitted from the headers. func (key *Key) GetArmoredPublicKeyWithCustomHeaders(comment, version string) (string, error) { serialized, err := key.GetPublicKey() if err != nil { return "", err } return armor.ArmorWithTypeAndCustomHeadersChecksum(serialized, constants.PublicKeyHeader, version, comment, !key.isV6()) } // GetPublicKey returns the unarmored public keys from this keyring. func (key *Key) GetPublicKey() (b []byte, err error) { var outBuf bytes.Buffer if err = key.entity.Serialize(&outBuf); err != nil { return nil, errors.Wrap(err, "gopenpgp: error in serializing public key") } return outBuf.Bytes(), nil } // --- Key object properties // CanVerify returns true if any of the subkeys can be used for verification. func (key *Key) CanVerify(unixTime int64) bool { _, canVerify := key.entity.SigningKey(time.Unix(unixTime, 0), nil) return canVerify } // CanEncrypt returns true if any of the subkeys can be used for encryption. func (key *Key) CanEncrypt(unixTime int64) bool { _, canEncrypt := key.entity.EncryptionKey(time.Unix(unixTime, 0), nil) return canEncrypt } // IsExpired checks whether the key is expired. func (key *Key) IsExpired(unixTime int64) bool { current := time.Unix(unixTime, 0) sig, err := key.entity.PrimarySelfSignature(time.Time{}, &packet.Config{}) if err != nil { return true } return key.entity.PrimaryKey.KeyExpired(sig, current) || // primary key has expired sig.SigExpired(current) // user ID self-signature has expired } // IsRevoked checks whether the key or the primary identity has a valid revocation signature. func (key *Key) IsRevoked(unixTime int64) bool { current := time.Unix(unixTime, 0) return key.entity.Revoked(current) } // IsPrivate returns true if the key is private. func (key *Key) IsPrivate() bool { return key.entity.PrivateKey != nil } // IsLocked checks if a private key is locked. func (key *Key) IsLocked() (bool, error) { if key.entity.PrivateKey == nil { return false, errors.New("gopenpgp: a public key cannot be locked") } encryptedKeys := 0 for _, sub := range key.entity.Subkeys { if sub.PrivateKey != nil && !sub.PrivateKey.Dummy() && sub.PrivateKey.Encrypted { encryptedKeys++ } } if key.entity.PrivateKey.Encrypted { encryptedKeys++ } return encryptedKeys > 0, nil } // IsUnlocked checks if a private key is unlocked. func (key *Key) IsUnlocked() (bool, error) { if key.entity.PrivateKey == nil { return true, errors.New("gopenpgp: a public key cannot be unlocked") } encryptedKeys := 0 for _, sub := range key.entity.Subkeys { if sub.PrivateKey != nil && !sub.PrivateKey.Dummy() && sub.PrivateKey.Encrypted { encryptedKeys++ } } if key.entity.PrivateKey.Encrypted { encryptedKeys++ } return encryptedKeys == 0, nil } // Check verifies if the public keys match the private key parameters by // signing and verifying. // Deprecated: all keys are now checked on parsing. func (key *Key) Check() (bool, error) { return true, nil } // PrintFingerprints is a debug helper function that prints the key and subkey fingerprints. func (key *Key) PrintFingerprints() { for _, subKey := range key.entity.Subkeys { binding, err := subKey.LatestValidBindingSignature(time.Time{}, &packet.Config{}) if err != nil { continue } if !binding.FlagsValid || binding.FlagEncryptStorage || binding.FlagEncryptCommunications { fmt.Println("SubKey:" + hex.EncodeToString(subKey.PublicKey.Fingerprint)) } } fmt.Println("PrimaryKey:" + hex.EncodeToString(key.entity.PrimaryKey.Fingerprint)) } // GetHexKeyID returns the key ID, hex encoded as a string. func (key *Key) GetHexKeyID() string { return keyIDToHex(key.GetKeyID()) } // GetKeyID returns the key ID, encoded as 8-byte int. // Does not work for go-mobile clients, use GetHexKeyID instead. func (key *Key) GetKeyID() uint64 { return key.entity.PrimaryKey.KeyId } // GetFingerprint gets the fingerprint from the key. func (key *Key) GetFingerprint() string { return hex.EncodeToString(key.entity.PrimaryKey.Fingerprint) } // GetFingerprintBytes gets the fingerprint from the key as a byte slice. func (key *Key) GetFingerprintBytes() []byte { return key.entity.PrimaryKey.Fingerprint } // GetSHA256Fingerprint computes the SHA256 fingerprint of the primary key. func (key *Key) GetSHA256Fingerprint() (fingerprint string) { return hex.EncodeToString(getSHA256FingerprintBytes(key.entity.PrimaryKey)) } // GetSHA256Fingerprints computes the SHA256 fingerprints of the key and subkeys. func (key *Key) GetSHA256Fingerprints() (fingerprints []string) { fingerprints = append(fingerprints, key.GetSHA256Fingerprint()) for _, sub := range key.entity.Subkeys { fingerprints = append(fingerprints, hex.EncodeToString(getSHA256FingerprintBytes(sub.PublicKey))) } return } // GetJsonSHA256Fingerprints returns the SHA256 fingerprints of key and subkeys // encoded in JSON, for gomobile clients that cannot handle arrays. func (key *Key) GetJsonSHA256Fingerprints() ([]byte, error) { return json.Marshal(key.GetSHA256Fingerprints()) } // GetEntity gets x/crypto Entity object. // Not supported on go-mobile clients. func (key *Key) GetEntity() *openpgp.Entity { return key.entity } // GetVersion returns the OpenPGP key packet version of this key. func (key *Key) GetVersion() int { return key.entity.PrimaryKey.Version } // ToPublic returns the corresponding public key of the given private key. func (key *Key) ToPublic() (publicKey *Key, err error) { if !key.IsPrivate() { return nil, errors.New("gopenpgp: key is already public") } publicKey, err = key.Copy() if err != nil { return nil, err } publicKey.ClearPrivateParams() return } func (key *Key) isV6() bool { if key == nil || key.entity == nil { return false } return key.entity.PrimaryKey.Version == 6 } // --- Internal methods // getSHA256FingerprintBytes computes the SHA256 fingerprint of a public key // object. func getSHA256FingerprintBytes(pk *packet.PublicKey) []byte { fingerPrint := sha256.New() // Hashing can't return an error, and has already been done when parsing the key, // hence the error is nil _ = pk.SerializeForHash(fingerPrint) return fingerPrint.Sum(nil) } // readFrom reads unarmored and armored keys from r and adds them to the keyring. func (key *Key) readFrom(r io.Reader, armored bool) error { var err error var entities openpgp.EntityList if armored { entities, err = openpgp.ReadArmoredKeyRing(r) } else { entities, err = openpgp.ReadKeyRing(r) } if err != nil { return errors.Wrap(err, "gopenpgp: error in reading key ring") } if len(entities) > 1 { return errors.New("gopenpgp: the key contains too many entities") } if len(entities) == 0 { return errors.New("gopenpgp: the key does not contain any entity") } key.entity = entities[0] return nil } func generateKeyWithConfig( name, email, comments string, config *packet.Config, ) (*Key, error) { if len(email) == 0 && len(name) == 0 { return nil, errors.New("gopenpgp: neither name nor email set.") } newEntity, err := openpgp.NewEntity(name, comments, email, config) if err != nil { return nil, errors.Wrap(err, "gopengpp: error in encoding new entity") } if newEntity.PrivateKey == nil { return nil, errors.New("gopenpgp: error in generating private key") } return NewKeyFromEntity(newEntity) } // keyIDToHex casts a keyID to hex with the correct padding. func keyIDToHex(keyID uint64) string { return fmt.Sprintf("%016v", strconv.FormatUint(keyID, 16)) } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/key_clear.go000066400000000000000000000070061472137411600244050ustar00rootroot00000000000000package crypto import ( "crypto/dsa" "crypto/rsa" "errors" "math/big" "github.com/ProtonMail/go-crypto/openpgp/ecdh" "github.com/ProtonMail/go-crypto/openpgp/ecdsa" "github.com/ProtonMail/go-crypto/openpgp/ed25519" "github.com/ProtonMail/go-crypto/openpgp/ed448" "github.com/ProtonMail/go-crypto/openpgp/eddsa" "github.com/ProtonMail/go-crypto/openpgp/elgamal" "github.com/ProtonMail/go-crypto/openpgp/x25519" "github.com/ProtonMail/go-crypto/openpgp/x448" ) // Clear zeroes the sensitive data in the session key. func (sk *SessionKey) Clear() (ok bool) { clearMem(sk.Key) return true } // ClearPrivateParams zeroes the sensitive data in the key. func (key *Key) ClearPrivateParams() (ok bool) { num := key.clearPrivateWithSubkeys() key.entity.PrivateKey = nil for k := range key.entity.Subkeys { key.entity.Subkeys[k].PrivateKey = nil } return num > 0 } func (key *Key) clearPrivateWithSubkeys() (num int) { num = 0 if key.entity.PrivateKey != nil { err := clearPrivateKey(key.entity.PrivateKey.PrivateKey) if err == nil { num++ } } for k := range key.entity.Subkeys { if key.entity.Subkeys[k].PrivateKey != nil { err := clearPrivateKey(key.entity.Subkeys[k].PrivateKey.PrivateKey) if err == nil { num++ } } } return num } func clearPrivateKey(privateKey interface{}) error { switch priv := privateKey.(type) { case *rsa.PrivateKey: return clearRSAPrivateKey(priv) case *dsa.PrivateKey: return clearDSAPrivateKey(priv) case *elgamal.PrivateKey: return clearElGamalPrivateKey(priv) case *ecdsa.PrivateKey: return clearECDSAPrivateKey(priv) case *eddsa.PrivateKey: return clearEdDSAPrivateKey(priv) case *ecdh.PrivateKey: return clearECDHPrivateKey(priv) case *x25519.PrivateKey: return clearX25519PrivateKey(priv) case *ed25519.PrivateKey: return clearEd25519PrivateKey(priv) case *x448.PrivateKey: return clearX448PrivateKey(priv) case *ed448.PrivateKey: return clearEd448PrivateKey(priv) default: return errors.New("gopenpgp: unknown private key") } } func clearBigInt(n *big.Int) { w := n.Bits() for k := range w { w[k] = 0x00 } } func clearMem(w []byte) { for k := range w { w[k] = 0x00 } } func clearRSAPrivateKey(rsaPriv *rsa.PrivateKey) error { clearBigInt(rsaPriv.D) for idx := range rsaPriv.Primes { clearBigInt(rsaPriv.Primes[idx]) } clearBigInt(rsaPriv.Precomputed.Qinv) clearBigInt(rsaPriv.Precomputed.Dp) clearBigInt(rsaPriv.Precomputed.Dq) for idx := range rsaPriv.Precomputed.CRTValues { clearBigInt(rsaPriv.Precomputed.CRTValues[idx].Exp) clearBigInt(rsaPriv.Precomputed.CRTValues[idx].Coeff) clearBigInt(rsaPriv.Precomputed.CRTValues[idx].R) } return nil } func clearDSAPrivateKey(priv *dsa.PrivateKey) error { clearBigInt(priv.X) return nil } func clearElGamalPrivateKey(priv *elgamal.PrivateKey) error { clearBigInt(priv.X) return nil } func clearECDSAPrivateKey(priv *ecdsa.PrivateKey) error { clearBigInt(priv.D) return nil } func clearEdDSAPrivateKey(priv *eddsa.PrivateKey) error { clearMem(priv.D) return nil } func clearECDHPrivateKey(priv *ecdh.PrivateKey) error { clearMem(priv.D) return nil } func clearX25519PrivateKey(priv *x25519.PrivateKey) error { clearMem(priv.Secret) return nil } func clearEd25519PrivateKey(priv *ed25519.PrivateKey) error { clearMem(priv.Key[:ed25519.SeedSize]) return nil } func clearX448PrivateKey(priv *x448.PrivateKey) error { clearMem(priv.Secret) return nil } func clearEd448PrivateKey(priv *ed448.PrivateKey) error { clearMem(priv.Key[:ed448.SeedSize]) return nil } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/key_generation.go000066400000000000000000000025451472137411600254550ustar00rootroot00000000000000package crypto import ( "github.com/ProtonMail/go-crypto/openpgp/packet" ) // Integer enum for go-mobile compatibility. const ( // KeyGenerationRSA4096 allows to override the output key algorithm in key generation to rsa 4096. KeyGenerationRSA4096 int = 1 // KeyGenerationCurve25519Legacy allows to override the output key algorithm in key generation to curve25519 legacy (as defined in RFC4880bis). KeyGenerationCurve25519Legacy int = 2 // KeyGenerationCurve25519 allows to override the output key algorithm in key generation to curve25519 (as defined in RFC9580). KeyGenerationCurve25519 int = 3 // KeyGenerationCurve448 allows to override the output key algorithm in key generation to curve448 (as defined in RFC9580). KeyGenerationCurve448 int = 4 ) type KeyGenerationProfile interface { KeyGenerationConfig(securityLevel int8) *packet.Config } // PGPKeyGeneration is an interface for generating pgp keys with GopenPGP. // Use the KeyGenerationBuilder to create a handle that implements PGPKeyGeneration. type PGPKeyGeneration interface { // GenerateKey generates a pgp key with the standard security level. GenerateKey() (*Key, error) // GenerateKeyWithSecurity generates a pgp key with the given security level. // The argument security allows to set the security level, either standard or high. GenerateKeyWithSecurity(securityLevel int8) (*Key, error) } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/key_generation_handle.go000066400000000000000000000057011472137411600267650ustar00rootroot00000000000000package crypto import ( "github.com/ProtonMail/go-crypto/openpgp/packet" openpgp "github.com/ProtonMail/go-crypto/openpgp/v2" "github.com/ProtonMail/gopenpgp/v3/constants" "github.com/pkg/errors" ) type identity struct { name, comment, email string } type keyGenerationHandle struct { identities []identity keyLifetimeSecs uint32 overrideAlgorithm int profile KeyGenerationProfile clock Clock } // --- Default key generation handle to build from func defaultKeyGenerationHandle(profile KeyGenerationProfile, clock Clock) *keyGenerationHandle { return &keyGenerationHandle{ clock: clock, profile: profile, } } // --- Implements PGPKeyGeneration interface // GenerateKey generates a pgp key with the standard security level. func (kgh *keyGenerationHandle) GenerateKey() (key *Key, err error) { return kgh.GenerateKeyWithSecurity(constants.StandardSecurity) } // GenerateKeyWithSecurity generates a pgp key with the given security level. // The argument security allows to set the security level, either standard or high. func (kgh *keyGenerationHandle) GenerateKeyWithSecurity(security int8) (key *Key, err error) { config := kgh.profile.KeyGenerationConfig(security) updateConfig(config, kgh.overrideAlgorithm) config.Time = NewConstantClock(kgh.clock().Unix()) config.KeyLifetimeSecs = kgh.keyLifetimeSecs key = &Key{} if len(kgh.identities) == 0 { if config.V6() { key.entity, err = openpgp.NewEntityWithoutId(config) } else { return nil, errors.New("gopenpgp: non-v6 key requires a user id") } } else { if err = kgh.identities[0].valid(); err != nil { return nil, err } key.entity, err = openpgp.NewEntity( kgh.identities[0].name, kgh.identities[0].comment, kgh.identities[0].email, config, ) } if err != nil { return nil, errors.Wrap(err, "gopengpp: error in creating new entity") } for id := 1; id < len(kgh.identities); id++ { if err = kgh.identities[id].valid(); err != nil { return nil, err } err = key.entity.AddUserId( kgh.identities[id].name, kgh.identities[id].comment, kgh.identities[id].email, config, ) if err != nil { return nil, errors.Wrap(err, "gopengpp: error in adding user id") } } if key.entity.PrivateKey == nil { return nil, errors.New("gopenpgp: error in generating private key") } return key, nil } func (id identity) valid() error { if len(id.email) == 0 && len(id.name) == 0 { return errors.New("gopenpgp: neither name nor email set in user id") } return nil } func updateConfig(config *packet.Config, algorithm int) { switch algorithm { case KeyGenerationRSA4096: config.Algorithm = packet.PubKeyAlgoRSA config.RSABits = 4096 case KeyGenerationCurve25519Legacy: config.V6Keys = false config.Algorithm = packet.PubKeyAlgoEdDSA config.Curve = packet.Curve25519 case KeyGenerationCurve25519: config.Algorithm = packet.PubKeyAlgoEd25519 case KeyGenerationCurve448: config.Algorithm = packet.PubKeyAlgoEd448 } } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/key_generation_handle_builder.go000066400000000000000000000036711472137411600304770ustar00rootroot00000000000000package crypto // KeyGenerationBuilder allows to configure a key generation handle to generate OpenPGP keys. type KeyGenerationBuilder struct { handle *keyGenerationHandle defaultClock Clock } func newKeyGenerationBuilder(profile KeyGenerationProfile, clock Clock) *KeyGenerationBuilder { return &KeyGenerationBuilder{ handle: defaultKeyGenerationHandle(profile, clock), defaultClock: clock, } } // GenerationTime sets the key generation time to the given unixTime. func (kgb *KeyGenerationBuilder) GenerationTime(unixTime int64) *KeyGenerationBuilder { kgb.handle.clock = NewConstantClock(unixTime) return kgb } // Lifetime sets the key lifetime to the given value in seconds. // The lifetime defaults to zero i.e., infinite lifetime. func (kgb *KeyGenerationBuilder) Lifetime(seconds int32) *KeyGenerationBuilder { kgb.handle.keyLifetimeSecs = uint32(seconds) return kgb } // AddUserId adds the provided user identity to any generated key. func (kgb *KeyGenerationBuilder) AddUserId(name, email string) *KeyGenerationBuilder { kgb.handle.identities = append(kgb.handle.identities, identity{name, "", email}) return kgb } // OverrideProfileAlgorithm allows to override the algorithm of the output key instead of using the profile's // algorithm with the respective security level. // // Allowed inputs (integer enum for go-mobile compatibility): // crypto.KeyGenerationRSA4096, crypto.KeyGenerationC25519, crypto.KeyGenerationC25519Refresh // crypto.KeyGenerationC448, crypto.KeyGenerationC448Refresh. func (kgb *KeyGenerationBuilder) OverrideProfileAlgorithm(algorithm int) *KeyGenerationBuilder { kgb.handle.overrideAlgorithm = algorithm return kgb } // New creates a new key generation handle from the internal configuration // that allows to generate pgp keys. func (kgb *KeyGenerationBuilder) New() PGPKeyGeneration { handle := kgb.handle kgb.handle = defaultKeyGenerationHandle(kgb.handle.profile, kgb.defaultClock) return handle } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/key_test.go000066400000000000000000000267131472137411600243040ustar00rootroot00000000000000package crypto import ( "io" "regexp" "strings" "testing" "time" "github.com/ProtonMail/go-crypto/openpgp/armor" "github.com/ProtonMail/go-crypto/openpgp/packet" openpgp "github.com/ProtonMail/go-crypto/openpgp/v2" "github.com/ProtonMail/gopenpgp/v3/constants" "github.com/ProtonMail/gopenpgp/v3/profile" "github.com/stretchr/testify/assert" ) const keyTestName = "Max Mustermann" const keyTestDomain = "max.mustermann@protonmail.ch" var keyTestPassphrase = []byte("I love GNU") var ( keyTestArmoredRSA string keyTestArmoredEC string keyTestRSA *Key keyTestEC *Key ) func initGenerateKeys() { var err error clock := NewConstantClock(testTime) keyTestRSA, err = generateKey( keyTestName, keyTestDomain, clock, profile.RFC4880(), constants.StandardSecurity, 0, ) if err != nil { panic("Cannot generate RSA key:" + err.Error()) } keyTestEC, err = generateKey( keyTestName, keyTestDomain, clock, profile.Default(), constants.StandardSecurity, 0, ) if err != nil { panic("Cannot generate EC key:" + err.Error()) } } func initArmoredKeys() { var err error lockedRSA, err := testPGP.LockKey(keyTestRSA, keyTestPassphrase) if err != nil { panic("Cannot lock RSA key:" + err.Error()) } keyTestArmoredRSA, err = lockedRSA.Armor() if err != nil { panic("Cannot armor protected RSA key:" + err.Error()) } lockedEC, err := testPGP.LockKey(keyTestEC, keyTestPassphrase) if err != nil { panic("Cannot lock EC key:" + err.Error()) } keyTestArmoredEC, err = lockedEC.Armor() if err != nil { panic("Cannot armor protected EC key:" + err.Error()) } } func TestArmorKeys(t *testing.T) { var err error noPasswordRSA, err := keyTestRSA.Armor() if err != nil { t.Fatal("Cannot armor unprotected RSA key:" + err.Error()) } noPasswordEC, err := keyTestEC.Armor() if err != nil { t.Fatal("Cannot armor unprotected EC key:" + err.Error()) } rTest := regexp.MustCompile(`(?s)^-----BEGIN PGP PRIVATE KEY BLOCK-----.*-----END PGP PRIVATE KEY BLOCK-----$`) assert.Regexp(t, rTest, noPasswordRSA) assert.Regexp(t, rTest, noPasswordEC) assert.Regexp(t, rTest, keyTestArmoredRSA) assert.Regexp(t, rTest, keyTestArmoredEC) } func TestArmorKeysWithCustomHeader(t *testing.T) { comment := "User-defined private key comment" version := "User-defined private key version" armored, err := keyTestRSA.ArmorWithCustomHeaders(comment, version) if err != nil { t.Fatal("Could not armor the private key:", err) } assert.Contains(t, armored, "Comment: "+comment) assert.Contains(t, armored, "Version: "+version) } func TestLockUnlockKeys(t *testing.T) { testLockUnlockKey(t, keyTestArmoredRSA, keyTestPassphrase) testLockUnlockKey(t, keyTestArmoredEC, keyTestPassphrase) testLockUnlockKey(t, readTestFile("keyring_privateKey", false), testMailboxPassword) publicKey, err := NewKeyFromArmored(readTestFile("keyring_publicKey", false)) if err != nil { t.Fatal("Cannot unarmor key:", err) } _, err = publicKey.IsLocked() if err == nil { t.Fatal("Should not be able to check locked on public key:") } _, err = publicKey.IsUnlocked() if err == nil { t.Fatal("Should not be able to check unlocked on public key:") } _, err = publicKey.Unlock(testMailboxPassword) if err == nil { t.Fatal("Should not be able to unlock public key:") } _, err = testPGP.LockKey(publicKey, keyTestPassphrase) if err == nil { t.Fatal("Should not be able to lock public key:") } } func testLockUnlockKey(t *testing.T, armoredKey string, pass []byte) { var err error lockedKey, err := NewKeyFromArmored(armoredKey) if err != nil { t.Fatal("Cannot unarmor key:", err) } // Check if key is locked locked, err := lockedKey.IsLocked() if err != nil { t.Fatal("Cannot check if key is unlocked:", err) } if !locked { t.Fatal("Key should be fully locked") } unlockedKey, err := lockedKey.Unlock(pass) if err != nil { t.Fatal("Cannot unlock key:", err) } // Check if key was successfully unlocked unlocked, err := unlockedKey.IsUnlocked() if err != nil { t.Fatal("Cannot check if key is unlocked:", err) } if !unlocked { t.Fatal("Key should be fully unlocked") } // Check if action is performed on copy locked, err = lockedKey.IsLocked() if err != nil { t.Fatal("Cannot check if key is unlocked:", err) } if !locked { t.Fatal("Key should be fully locked") } // re-lock key relockedKey, err := testPGP.LockKey(unlockedKey, keyTestPassphrase) if err != nil { t.Fatal("Cannot lock key:", err) } // Check if key was successfully locked relocked, err := relockedKey.IsLocked() if err != nil { t.Fatal("Cannot check if key is unlocked:", err) } if !relocked { t.Fatal("Key should be fully locked") } // Check if action is performed on copy unlocked, err = unlockedKey.IsUnlocked() if err != nil { t.Fatal("Cannot check if key is unlocked:", err) } if !unlocked { t.Fatal("Key should be fully unlocked") } } func ExampleKey_PrintFingerprints() { keyringKey, _ := NewKeyFromArmored(readTestFile("keyring_publicKey", false)) keyringKey.PrintFingerprints() // Output: // SubKey:37e4bcf09b36e34012d10c0247dc67b5cb8267f6 // PrimaryKey:6e8ba229b0cccaf6962f97953eb6259edf21df24 } func TestIsExpired(t *testing.T) { assert.False(t, keyTestRSA.IsExpired(testTime)) assert.False(t, keyTestEC.IsExpired(testTime)) expiredKey, err := NewKeyFromArmored(readTestFile("key_expiredKey", false)) if err != nil { t.Fatal("Cannot unarmor expired key:", err) } futureKey, err := NewKeyFromArmored(readTestFile("key_futureKey", false)) if err != nil { t.Fatal("Cannot unarmor future key:", err) } assert.True(t, expiredKey.IsExpired(testTime)) assert.True(t, futureKey.IsExpired(testTime)) } func TestGetPublicKey(t *testing.T) { publicKey, err := keyTestRSA.GetPublicKey() if err != nil { t.Fatal("Expected no error while obtaining public key, got:", err) } decodedKey, err := NewKey(publicKey) if err != nil { t.Fatal("Expected no error while creating public key, got:", err) } privateFingerprint := keyTestRSA.GetFingerprint() publicFingerprint := decodedKey.GetFingerprint() assert.False(t, decodedKey.IsPrivate()) assert.True(t, keyTestRSA.IsPrivate()) assert.Exactly(t, privateFingerprint, publicFingerprint) } func TestGetArmoredPublicKey(t *testing.T) { privateKey, err := NewKeyFromArmored(readTestFile("keyring_privateKey", false)) if err != nil { t.Fatal("Expected no error while unarmoring private key, got:", err) } s, err := privateKey.GetArmoredPublicKey() if err != nil { t.Fatal("Expected no error while getting armored public key, got:", err) } // Decode armored keys block, err := armor.Decode(strings.NewReader(s)) if err != nil { t.Fatal("Expected no error while decoding armored public key, got:", err) } expected, err := armor.Decode(strings.NewReader(readTestFile("keyring_publicKey", false))) if err != nil { t.Fatal("Expected no error while decoding expected armored public key, got:", err) } assert.Exactly(t, expected.Type, block.Type) b, err := io.ReadAll(block.Body) if err != nil { t.Fatal("Expected no error while reading armored public key body, got:", err) } eb, err := io.ReadAll(expected.Body) if err != nil { t.Fatal("Expected no error while reading expected armored public key body, got:", err) } assert.Exactly(t, eb, b) publicKey, err := keyTestRSA.GetArmoredPublicKey() if err != nil { t.Fatal("Expected no error while obtaining armored public key, got:", err) } decodedKey, err := NewKeyFromArmored(publicKey) if err != nil { t.Fatal("Expected no error while creating public key from armored, got:", err) } assert.False(t, decodedKey.IsPrivate()) assert.True(t, keyTestRSA.IsPrivate()) privateFingerprint := keyTestRSA.GetFingerprint() publicFingerprint := decodedKey.GetFingerprint() assert.Exactly(t, privateFingerprint, publicFingerprint) } func TestGetArmoredPublicKeyWithCustomHeaders(t *testing.T) { comment := "User-defined public key comment" version := "User-defined public key version" armored, err := keyTestRSA.GetArmoredPublicKeyWithCustomHeaders(comment, version) if err != nil { t.Fatal("Could not armor the public key:", err) } assert.Contains(t, armored, "Comment: "+comment) assert.Contains(t, armored, "Version: "+version) } func TestGetArmoredPublicKeyWithEmptyCustomHeaders(t *testing.T) { armored, err := keyTestRSA.GetArmoredPublicKeyWithCustomHeaders("", "") if err != nil { t.Fatal("Could not armor the public key:", err) } assert.NotContains(t, armored, "Version") assert.NotContains(t, armored, "Comment") } func TestGetSHA256FingerprintsV4(t *testing.T) { publicKey, err := NewKeyFromArmored(readTestFile("keyring_publicKey", false)) if err != nil { t.Fatal("Cannot unarmor key:", err) } sha256Fingerprints := publicKey.GetSHA256Fingerprints() assert.Len(t, sha256Fingerprints, 2) assert.Exactly(t, "d9ac0b857da6d2c8be985b251a9e3db31e7a1d2d832d1f07ebe838a9edce9c24", sha256Fingerprints[0]) assert.Exactly(t, "203dfba1f8442c17e59214d9cd11985bfc5cc8721bb4a71740dd5507e58a1a0d", sha256Fingerprints[1]) assert.Exactly(t, "d9ac0b857da6d2c8be985b251a9e3db31e7a1d2d832d1f07ebe838a9edce9c24", publicKey.GetSHA256Fingerprint()) } func TestGetEntity(t *testing.T) { publicKey, err := NewKeyFromArmored(readTestFile("keyring_publicKey", false)) if err != nil { t.Fatal("Cannot unarmor key:", err) } entity := publicKey.GetEntity() selfSig, err := entity.PrimarySelfSignature(time.Unix(testTime, 0), &packet.Config{}) if err != nil { t.Fatal("Expected no error, got: ", err) } assert.True(t, selfSig.FlagsValid) assert.IsType(t, &openpgp.Entity{}, entity) } func TestToPublic(t *testing.T) { privateKey, err := NewKeyFromArmored(readTestFile("keyring_privateKey", false)) if err != nil { t.Fatal("Cannot unarmor key:", err) } assert.True(t, privateKey.IsPrivate()) publicKey, err := privateKey.ToPublic() if err != nil { t.Fatal("Cannot make key public:", err) } assert.False(t, publicKey.IsPrivate()) assert.True(t, privateKey.IsPrivate()) } func TestKeyCapabilities(t *testing.T) { assert.True(t, keyTestEC.CanVerify(testTime)) assert.True(t, keyTestEC.CanEncrypt(testTime)) assert.True(t, keyTestRSA.CanVerify(testTime)) assert.True(t, keyTestRSA.CanEncrypt(testTime)) publicKey, err := keyTestEC.ToPublic() if err != nil { t.Fatal("Cannot make key public:", err) } assert.True(t, publicKey.CanVerify(testTime)) assert.True(t, publicKey.CanEncrypt(testTime)) } const testRevokedKeyCapabilitiesTime = 1632219895 func TestRevokedKeyCapabilities(t *testing.T) { revokedKey, err := NewKeyFromArmored(readTestFile("key_revoked", false)) if err != nil { t.Fatal("Cannot unarmor key:", err) } assert.False(t, revokedKey.CanVerify(testRevokedKeyCapabilitiesTime)) assert.False(t, revokedKey.CanEncrypt(testRevokedKeyCapabilitiesTime)) assert.False(t, revokedKey.IsExpired(testRevokedKeyCapabilitiesTime)) assert.True(t, revokedKey.IsRevoked(testRevokedKeyCapabilitiesTime)) } func TestUnlockMismatchingKey(t *testing.T) { privateKey, err := NewKeyFromArmored(readTestFile("key_mismatching_eddsa_key", false)) if err != nil { t.Fatal("Expected no error while unarmoring private key, got:", err) } if _, err = privateKey.Unlock([]byte("123")); err == nil { t.Fatalf("Mismatching private key was not detected") } } func TestKeyCompression(t *testing.T) { selfSig, err := keyTestEC.entity.PrimarySelfSignature(time.Time{}, &packet.Config{}) if err != nil { t.Fatal("no error expected, got: ", err) } assert.Equal( t, []uint8{uint8(packet.CompressionNone), uint8(packet.CompressionZLIB)}, selfSig.PreferredCompression, ) } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/keyring.go000066400000000000000000000221201472137411600241110ustar00rootroot00000000000000package crypto import ( "bytes" "encoding/json" "time" "github.com/ProtonMail/go-crypto/openpgp/packet" openpgp "github.com/ProtonMail/go-crypto/openpgp/v2" "github.com/pkg/errors" ) // KeyRing contains multiple private and public keys. type KeyRing struct { // PGP entities in this keyring. entities openpgp.EntityList // FirstKeyID as obtained from API to match salt FirstKeyID string } // Identity contains the name and the email of a key holder. type Identity struct { Name string `json:"name"` Email string `json:"email"` } // --- New keyrings // NewKeyRing creates a new KeyRing, empty if key is nil. func NewKeyRing(key *Key) (*KeyRing, error) { keyRing := &KeyRing{} var err error if key != nil { err = keyRing.AddKey(key) } return keyRing, err } // AddKey adds the given key to the keyring. func (keyRing *KeyRing) AddKey(key *Key) error { if key.IsPrivate() { unlocked, err := key.IsUnlocked() if err != nil || !unlocked { return errors.New("gopenpgp: unable to add locked key to a keyring") } } keyRing.appendKey(key) return nil } // NewKeyRingFromBinary creates a new keyring with all the keys contained in the unarmored binary data. // Note that it accepts only unlocked or public keys, as KeyRing cannot contain locked keys. func NewKeyRingFromBinary(binKeys []byte) (*KeyRing, error) { entities, err := openpgp.ReadKeyRing(bytes.NewReader(binKeys)) if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in reading keyring") } keyring := &KeyRing{} for _, entity := range entities { key, err := NewKeyFromEntity(entity) if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in reading keyring") } if err = keyring.AddKey(key); err != nil { return nil, errors.Wrap(err, "gopenpgp: error in reading keyring") } } return keyring, nil } // --- Extract keys from keyring // GetKeys returns openpgp keys contained in this KeyRing. // Not supported on go mobile clients. func (keyRing *KeyRing) GetKeys() []*Key { keys := make([]*Key, keyRing.CountEntities()) for i, entity := range keyRing.entities { keys[i] = &Key{entity} } return keys } // GetKey returns the n-th openpgp key contained in this KeyRing. func (keyRing *KeyRing) GetKey(n int) (*Key, error) { if n >= keyRing.CountEntities() { return nil, errors.New("gopenpgp: out of bound when fetching key") } return &Key{keyRing.entities[n]}, nil } func (keyRing *KeyRing) signingEntities() ([]*openpgp.Entity, error) { var signEntity []*openpgp.Entity for _, e := range keyRing.entities { // Entity.PrivateKey must be a signing key if e.PrivateKey != nil && !e.PrivateKey.Encrypted { signEntity = append(signEntity, e) } else { return nil, errors.New("gopenpgp: signing entity does not contain unencrypted private key") } } return signEntity, nil } // getEntities returns the internal EntityList if the key ring is not nil. func (keyRing *KeyRing) getEntities() openpgp.EntityList { if keyRing == nil { return nil } return keyRing.entities } // Serialize serializes a KeyRing to binary data. func (keyRing *KeyRing) Serialize() ([]byte, error) { var buffer bytes.Buffer for _, entity := range keyRing.entities { var err error if entity.PrivateKey == nil { err = entity.Serialize(&buffer) } else { err = entity.SerializePrivateWithoutSigning(&buffer, nil) } if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in serializing keyring") } } return buffer.Bytes(), nil } // --- Extract info from key // CountEntities returns the number of entities in the keyring. func (keyRing *KeyRing) CountEntities() int { if keyRing == nil { return 0 } return len(keyRing.entities) } // CountDecryptionEntities returns the number of entities in the keyring. // Takes the current time for checking the keys in unix time format. // If the unix time is zero, time checks are ignored. func (keyRing *KeyRing) CountDecryptionEntities(unixTime int64) int { var count int var checkTime time.Time if unixTime != 0 { checkTime = time.Unix(unixTime, 0) } for _, entity := range keyRing.entities { decryptionKeys := entity.DecryptionKeys(0, checkTime, &packet.Config{}) count += len(decryptionKeys) } return count } // GetIdentities returns the list of identities associated with this key ring. // Not supported on go-mobile clients use keyRing.GetIdentitiesJson() instead. func (keyRing *KeyRing) GetIdentities() []*Identity { var identities []*Identity for _, e := range keyRing.entities { for _, id := range e.Identities { identities = append(identities, &Identity{ Name: id.UserId.Name, Email: id.UserId.Email, }) } } return identities } // GetIdentitiesJson returns the list of identities associated with this key ring encoded as json. // Returns nil if an encoding error occurs. // Helper function for go-mobile clients. func (keyRing *KeyRing) GetIdentitiesJson() []byte { identitiesJson, err := json.Marshal(keyRing.GetIdentities()) if err != nil { return nil } return identitiesJson } // CanVerify returns true if any of the keys in the keyring can be used for verification. func (keyRing *KeyRing) CanVerify(unixTime int64) bool { keys := keyRing.GetKeys() for _, key := range keys { if key.CanVerify(unixTime) { return true } } return false } // CanEncrypt returns true if any of the keys in the keyring can be used for encryption. func (keyRing *KeyRing) CanEncrypt(unixTime int64) bool { keys := keyRing.GetKeys() for _, key := range keys { if key.CanEncrypt(unixTime) { return true } } return false } // GetKeyIDs returns array of IDs of keys in this KeyRing. // Not supported on go-mobile clients. func (keyRing *KeyRing) GetKeyIDs() []uint64 { var res = make([]uint64, len(keyRing.entities)) for id, e := range keyRing.entities { res[id] = e.PrimaryKey.KeyId } return res } // GetHexKeyIDsJson returns an IDs of keys in this KeyRing as a json array. // Key ids are encoded as hexadecimal and nil is returned if an error occurs. // Helper function for go-mobile clients. func (keyRing *KeyRing) GetHexKeyIDsJson() []byte { var res = make([]string, len(keyRing.entities)) for id, e := range keyRing.entities { res[id] = keyIDToHex(e.PrimaryKey.KeyId) } keyIdsJson, err := json.Marshal(res) if err != nil { return nil } return keyIdsJson } // --- Filter keyrings // FilterExpiredKeys takes a given KeyRing list and it returns only those // KeyRings which contain at least, one unexpired Key. It returns only unexpired // parts of these KeyRings. func FilterExpiredKeys(contactKeys []*KeyRing) (filteredKeys []*KeyRing, err error) { now := time.Now() hasExpiredEntity := false filteredKeys = make([]*KeyRing, 0) for _, contactKeyRing := range contactKeys { keyRingHasUnexpiredEntity := false keyRingHasTotallyExpiredEntity := false for _, entity := range contactKeyRing.entities { hasExpired := false hasUnexpired := false for _, subkey := range entity.Subkeys { latestValid, err := subkey.LatestValidBindingSignature(now, &packet.Config{}) if err != nil { hasExpired = true } if subkey.PublicKey.KeyExpired(latestValid, now) { hasExpired = true } else { hasUnexpired = true } } if hasExpired && !hasUnexpired { keyRingHasTotallyExpiredEntity = true } else if hasUnexpired { keyRingHasUnexpiredEntity = true } } if keyRingHasUnexpiredEntity { keyRingCopy, err := contactKeyRing.Copy() if err != nil { return nil, err } filteredKeys = append(filteredKeys, keyRingCopy) } else if keyRingHasTotallyExpiredEntity { hasExpiredEntity = true } } if len(filteredKeys) == 0 && hasExpiredEntity { return filteredKeys, errors.New("gopenpgp: all contacts keys are expired") } return filteredKeys, nil } // FirstKey returns a KeyRing with only the first key of the original one. func (keyRing *KeyRing) FirstKey() (*KeyRing, error) { if len(keyRing.entities) == 0 { return nil, errors.New("gopenpgp: No key available in this keyring") } newKeyRing := &KeyRing{} newKeyRing.entities = keyRing.entities[:1] return newKeyRing.Copy() } // Copy creates a deep copy of the keyring. func (keyRing *KeyRing) Copy() (*KeyRing, error) { newKeyRing := &KeyRing{} entities := make([]*openpgp.Entity, len(keyRing.entities)) for id, entity := range keyRing.entities { var buffer bytes.Buffer var err error if entity.PrivateKey == nil { err = entity.Serialize(&buffer) } else { err = entity.SerializePrivateWithoutSigning(&buffer, nil) } if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to copy key: error in serializing entity") } bt := buffer.Bytes() entities[id], err = openpgp.ReadEntity(packet.NewReader(bytes.NewReader(bt))) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to copy key: error in reading entity") } } newKeyRing.entities = entities newKeyRing.FirstKeyID = keyRing.FirstKeyID return newKeyRing, nil } func (keyRing *KeyRing) ClearPrivateParams() { for _, key := range keyRing.GetKeys() { key.ClearPrivateParams() } } // INTERNAL FUNCTIONS // appendKey appends a key to the keyring. func (keyRing *KeyRing) appendKey(key *Key) { keyRing.entities = append(keyRing.entities, key.entity) } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/keyring_test.go000066400000000000000000000143071472137411600251600ustar00rootroot00000000000000package crypto import ( "crypto/rsa" "testing" "github.com/stretchr/testify/assert" "github.com/ProtonMail/go-crypto/openpgp/ecdh" "github.com/ProtonMail/go-crypto/openpgp/eddsa" ) var testSymmetricKey []byte // Password for key in testdata/keyring_privateKeyLegacy: "123". // Corresponding key in testdata/keyring_privateKey. var testMailboxPassword = []byte("apple") var ( keyRingTestPrivate *KeyRing keyRingTestPublic *KeyRing keyRingTestMultiple *KeyRing ) var testIdentity = &Identity{ Name: "UserID", Email: "", } func initKeyRings() { var err error testSymmetricKey, err = RandomToken(32) if err != nil { panic("Expected no error while generating random token, got:" + err.Error()) } privateKey, err := NewKeyFromArmored(readTestFile("keyring_privateKey", false)) if err != nil { panic("Expected no error while unarmoring private key, got:" + err.Error()) } keyRingTestPrivate, err = NewKeyRing(privateKey) if err == nil { panic("Able to create a keyring with a locked key") } unlockedKey, err := privateKey.Unlock(testMailboxPassword) if err != nil { panic("Expected no error while unlocking private key, got:" + err.Error()) } keyRingTestPrivate, err = NewKeyRing(unlockedKey) if err != nil { panic("Expected no error while building private keyring, got:" + err.Error()) } publicKey, err := NewKeyFromArmored(readTestFile("keyring_publicKey", false)) if err != nil { panic("Expected no error while unarmoring public key, got:" + err.Error()) } keyRingTestPublic, err = NewKeyRing(publicKey) if err != nil { panic("Expected no error while building public keyring, got:" + err.Error()) } keyRingTestMultiple, err = NewKeyRing(nil) if err != nil { panic("Expected no error while building empty keyring, got:" + err.Error()) } err = keyRingTestMultiple.AddKey(keyTestRSA) if err != nil { panic("Expected no error while adding RSA key to keyring, got:" + err.Error()) } err = keyRingTestMultiple.AddKey(keyTestEC) if err != nil { panic("Expected no error while adding EC key to keyring, got:" + err.Error()) } err = keyRingTestMultiple.AddKey(unlockedKey) if err != nil { panic("Expected no error while adding unlocked key to keyring, got:" + err.Error()) } } func TestIdentities(t *testing.T) { identities := keyRingTestPrivate.GetIdentities() assert.Len(t, identities, 1) assert.Exactly(t, identities[0], testIdentity) } func TestFilterExpiredKeys(t *testing.T) { expiredKey, err := NewKeyFromArmored(readTestFile("key_expiredKey", false)) if err != nil { t.Fatal("Cannot unarmor expired key:", err) } expiredKeyRing, err := NewKeyRing(expiredKey) if err != nil { t.Fatal("Cannot create keyring with expired key:", err) } keys := []*KeyRing{keyRingTestPrivate, expiredKeyRing} unexpired, err := FilterExpiredKeys(keys) if err != nil { t.Fatal("Expected no error while filtering expired keyrings, got:", err) } assert.Len(t, unexpired, 1) assert.Exactly(t, unexpired[0].GetKeyIDs(), keyRingTestPrivate.GetKeyIDs()) } func TestKeyIds(t *testing.T) { keyIDs := keyRingTestPrivate.GetKeyIDs() var assertKeyIDs = []uint64{4518840640391470884} assert.Exactly(t, assertKeyIDs, keyIDs) } func TestMultipleKeyRing(t *testing.T) { assert.Exactly(t, 3, len(keyRingTestMultiple.entities)) assert.Exactly(t, 3, keyRingTestMultiple.CountEntities()) assert.Exactly(t, 3, keyRingTestMultiple.CountDecryptionEntities(testTime)) assert.Exactly(t, 3, len(keyRingTestMultiple.GetKeys())) testKey, err := keyRingTestMultiple.GetKey(1) if err != nil { t.Fatal("Expected no error while extracting key, got:", err) } assert.Exactly(t, keyTestEC, testKey) _, err = keyRingTestMultiple.GetKey(3) assert.NotNil(t, err) singleKeyRing, err := keyRingTestMultiple.FirstKey() if err != nil { t.Fatal("Expected no error while filtering the first key, got:", err) } assert.Exactly(t, 1, len(singleKeyRing.entities)) assert.Exactly(t, 1, singleKeyRing.CountEntities()) assert.Exactly(t, 1, singleKeyRing.CountDecryptionEntities(testTime)) } func TestSerializeParse(t *testing.T) { serialized, err := keyRingTestMultiple.Serialize() assert.Nil(t, err) parsed, err := NewKeyRingFromBinary(serialized) assert.Nil(t, err) assert.Exactly(t, 3, len(parsed.GetKeys())) for i, parsedKey := range parsed.GetKeys() { expectedKey, err := keyRingTestMultiple.GetKey(i) assert.Nil(t, err) assert.Exactly(t, parsedKey.GetFingerprint(), expectedKey.GetFingerprint()) } } func TestClearPrivateKey(t *testing.T) { keyRingCopy, err := keyRingTestMultiple.Copy() if err != nil { t.Fatal("Expected no error while copying keyring, got:", err) } for _, key := range keyRingCopy.GetKeys() { assert.Nil(t, clearPrivateKey(key.entity.PrivateKey.PrivateKey)) } keys := keyRingCopy.GetKeys() assertRSACleared(t, keys[0].entity.PrivateKey.PrivateKey.(*rsa.PrivateKey)) assertEdDSACleared(t, keys[1].entity.PrivateKey.PrivateKey.(*eddsa.PrivateKey)) assertRSACleared(t, keys[2].entity.PrivateKey.PrivateKey.(*rsa.PrivateKey)) } func TestClearPrivateWithSubkeys(t *testing.T) { keyRingCopy, err := keyRingTestMultiple.Copy() if err != nil { t.Fatal("Expected no error while copying keyring, got:", err) } for _, key := range keyRingCopy.GetKeys() { assert.Exactly(t, 2, key.clearPrivateWithSubkeys()) } keys := keyRingCopy.GetKeys() assertRSACleared(t, keys[0].entity.PrivateKey.PrivateKey.(*rsa.PrivateKey)) assertRSACleared(t, keys[0].entity.Subkeys[0].PrivateKey.PrivateKey.(*rsa.PrivateKey)) assertEdDSACleared(t, keys[1].entity.PrivateKey.PrivateKey.(*eddsa.PrivateKey)) assertECDHCleared(t, keys[1].entity.Subkeys[0].PrivateKey.PrivateKey.(*ecdh.PrivateKey)) assertRSACleared(t, keys[2].entity.PrivateKey.PrivateKey.(*rsa.PrivateKey)) assertRSACleared(t, keys[2].entity.Subkeys[0].PrivateKey.PrivateKey.(*rsa.PrivateKey)) } func TestClearPrivateParams(t *testing.T) { keyRingCopy, err := keyRingTestMultiple.Copy() if err != nil { t.Fatal("Expected no error while copying keyring, got:", err) } for _, key := range keyRingCopy.GetKeys() { assert.True(t, key.IsPrivate()) assert.True(t, key.ClearPrivateParams()) assert.False(t, key.IsPrivate()) assert.Nil(t, key.entity.PrivateKey) assert.Nil(t, key.entity.Subkeys[0].PrivateKey) assert.False(t, key.ClearPrivateParams()) } } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/message.go000066400000000000000000000333741472137411600241020ustar00rootroot00000000000000package crypto import ( "bytes" "encoding/json" goerrors "errors" "io" "regexp" "github.com/ProtonMail/go-crypto/openpgp/packet" "github.com/ProtonMail/gopenpgp/v3/armor" "github.com/ProtonMail/gopenpgp/v3/constants" "github.com/ProtonMail/gopenpgp/v3/internal" "github.com/pkg/errors" ) // ---- MODELS ----- type LiteralMetadata struct { // If the content is text or binary isUTF8 bool // The encrypted message's filename filename string // The file's latest modification time ModTime int64 } // PGPMessage stores a PGP-encrypted message. type PGPMessage struct { // KeyPacket references the PKESK and SKESK packets of the message KeyPacket []byte // DataPacket references the SEIPD or AEAD protected packet of the message DataPacket []byte // DetachedSignature stores the encrypted detached signature. // Nil when the signature is embedded in the data packet or not present. DetachedSignature []byte // detachedSignatureIsPlain indicates if the detached signature is not encrypted. detachedSignatureIsPlain bool // Signals that no armor checksum must be appended when armoring omitArmorChecksum bool } type PGPMessageBuffer struct { key *bytes.Buffer data *bytes.Buffer signature *bytes.Buffer } // ---- GENERATORS ----- // NewFileMetadata creates literal metadata. func NewFileMetadata(isUTF8 bool, filename string, modTime int64) *LiteralMetadata { return &LiteralMetadata{isUTF8: isUTF8, filename: filename, ModTime: modTime} } // NewMetadata creates new default literal metadata with utf-8 set to isUTF8. func NewMetadata(isUTF8 bool) *LiteralMetadata { return &LiteralMetadata{isUTF8: isUTF8} } // NewPGPMessage generates a new PGPMessage from the unarmored binary data. // Clones the data for go-mobile compatibility. func NewPGPMessage(data []byte) *PGPMessage { return NewPGPMessageWithCloneFlag(data, true) } // NewPGPMessageWithCloneFlag generates a new PGPMessage from the unarmored binary data. func NewPGPMessageWithCloneFlag(data []byte, doClone bool) *PGPMessage { packetData := data if doClone { packetData = clone(data) } pgpMessage := &PGPMessage{ DataPacket: packetData, } pgpMessage, err := pgpMessage.splitMessage() if err != nil { // If there is an error in split treat the data as data packets. return &PGPMessage{ DataPacket: packetData, } } return pgpMessage } // NewPGPMessageFromArmored generates a new PGPMessage from an armored string ready for decryption. func NewPGPMessageFromArmored(armored string) (*PGPMessage, error) { encryptedIO, err := internal.Unarmor(armored) if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in unarmoring message") } message, err := io.ReadAll(encryptedIO.Body) if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in reading armored message") } pgpMessage := &PGPMessage{ DataPacket: message, } pgpMessage, err = pgpMessage.splitMessage() if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in splitting message") } return pgpMessage, nil } // NewPGPSplitMessage generates a new PGPSplitMessage from the binary unarmored keypacket and datapacket. // Clones the slices for go-mobile compatibility. func NewPGPSplitMessage(keyPacket []byte, dataPacket []byte) *PGPMessage { return &PGPMessage{ KeyPacket: clone(keyPacket), DataPacket: clone(dataPacket), } } // NewPGPMessageBuffer creates a message buffer. func NewPGPMessageBuffer() *PGPMessageBuffer { return &PGPMessageBuffer{ key: new(bytes.Buffer), data: new(bytes.Buffer), signature: new(bytes.Buffer), } } // ---- MODEL METHODS ----- // Bytes returns the unarmored binary content of the message as a []byte. func (msg *PGPMessage) Bytes() []byte { return append(msg.KeyPacket, msg.DataPacket...) } // NewReader returns a New io.Reader for the unarmored binary data of the // message. // Not supported on go-mobile clients. func (msg *PGPMessage) NewReader() io.Reader { return bytes.NewReader(msg.Bytes()) } // Armor returns the armored message as a string. func (msg *PGPMessage) Armor() (string, error) { if msg.KeyPacket == nil { return "", errors.New("gopenpgp: missing key packets in pgp message") } if msg.omitArmorChecksum { return armor.ArmorPGPMessageChecksum(msg.Bytes(), false) } return armor.ArmorPGPMessage(msg.Bytes()) } // ArmorBytes returns the armored message as a string. func (msg *PGPMessage) ArmorBytes() ([]byte, error) { if msg.KeyPacket == nil { return nil, errors.New("gopenpgp: missing key packets in pgp message") } if msg.omitArmorChecksum { return armor.ArmorPGPMessageBytesChecksum(msg.Bytes(), false) } return armor.ArmorPGPMessageBytes(msg.Bytes()) } // ArmorWithCustomHeaders returns the armored message as a string, with // the given headers. Empty parameters are omitted from the headers. func (msg *PGPMessage) ArmorWithCustomHeaders(comment, version string) (string, error) { if msg.omitArmorChecksum { return armor.ArmorWithTypeAndCustomHeadersChecksum(msg.Bytes(), constants.PGPMessageHeader, version, comment, false) } return armor.ArmorWithTypeAndCustomHeaders(msg.Bytes(), constants.PGPMessageHeader, version, comment) } // EncryptionKeyIDs Returns the key IDs of the keys to which the session key is encrypted. // Not supported on go-mobile clients use msg.HexEncryptionKeyIDsJson() instead. func (msg *PGPMessage) EncryptionKeyIDs() ([]uint64, bool) { packets := packet.NewReader(bytes.NewReader(msg.KeyPacket)) var err error var ids []uint64 var encryptedKey *packet.EncryptedKey Loop: for { var p packet.Packet if p, err = packets.Next(); goerrors.Is(err, io.EOF) { break } switch p := p.(type) { case *packet.EncryptedKey: encryptedKey = p ids = append(ids, encryptedKey.KeyId) case *packet.SymmetricallyEncrypted, *packet.AEADEncrypted, *packet.Compressed, *packet.LiteralData: break Loop } } if len(ids) > 0 { return ids, true } return ids, false } // HexEncryptionKeyIDs returns the key IDs of the keys to which the session key is encrypted. // Not supported on go-mobile clients use msg.HexEncryptionKeyIDsJson() instead. func (msg *PGPMessage) HexEncryptionKeyIDs() ([]string, bool) { return hexKeyIDs(msg.EncryptionKeyIDs()) } // HexEncryptionKeyIDsJson returns the key IDs of the keys to which the session key is encrypted as a JSON array. // If an error occurs it returns nil. // Helper function for go-mobile clients. func (msg *PGPMessage) HexEncryptionKeyIDsJson() []byte { hexIds, ok := msg.HexEncryptionKeyIDs() if !ok { return nil } hexIdsJson, err := json.Marshal(hexIds) if err != nil { return nil } return hexIdsJson } // SignatureKeyIDs returns the key IDs of the keys to which the (readable) signature packets are encrypted to. // Not supported on go-mobile clients use msg.HexSignatureKeyIDsJson() instead. func (msg *PGPMessage) SignatureKeyIDs() ([]uint64, bool) { return SignatureKeyIDs(msg.DataPacket) } // HexSignatureKeyIDs returns the key IDs of the keys to which the session key is encrypted. // Not supported on go-mobile clients use msg.HexSignatureKeyIDsJson() instead. func (msg *PGPMessage) HexSignatureKeyIDs() ([]string, bool) { return hexKeyIDs(msg.SignatureKeyIDs()) } // HexSignatureKeyIDsJson returns the key IDs of the keys to which the session key is encrypted as a JSON array. // If an error occurs it returns nil. // Helper function for go-mobile clients. func (msg *PGPMessage) HexSignatureKeyIDsJson() []byte { sigHexSigIds, ok := msg.HexSignatureKeyIDs() if !ok { return nil } sigHexKeyIdsJSON, err := json.Marshal(sigHexSigIds) if err != nil { return nil } return sigHexKeyIdsJSON } // BinaryDataPacket returns the unarmored binary datapacket as a []byte. func (msg *PGPMessage) BinaryDataPacket() []byte { return msg.DataPacket } // BinaryKeyPacket returns the unarmored binary keypacket as a []byte. func (msg *PGPMessage) BinaryKeyPacket() []byte { return msg.KeyPacket } // EncryptedDetachedSignature returns the encrypted detached signature of this message // as a PGPMessage where the data is the encrypted signature. // If no detached signature is present in this message, it returns nil. func (msg *PGPMessage) EncryptedDetachedSignature() *PGPMessage { if msg.DetachedSignature == nil || msg.detachedSignatureIsPlain { return nil } return &PGPMessage{ KeyPacket: msg.KeyPacket, DataPacket: msg.DetachedSignature, } } // PlainDetachedSignature returns the plaintext detached signature of this message. // If no plaintext detached signature is present in this message, it returns an error. func (msg *PGPMessage) PlainDetachedSignature() ([]byte, error) { if msg.DetachedSignature == nil || !msg.detachedSignatureIsPlain { return nil, errors.New("gopenpgp: no plaintext detached signature found") } return msg.DetachedSignature, nil } // PlainDetachedSignatureArmor returns the armored plaintext detached signature of this message. // If no plaintext detached signature is present or armoring fails it returns an error. func (msg *PGPMessage) PlainDetachedSignatureArmor() ([]byte, error) { if msg.DetachedSignature == nil || !msg.detachedSignatureIsPlain { return nil, errors.New("gopenpgp: no plaintext detached signature found") } return armor.ArmorPGPSignatureBinary(msg.DetachedSignature) } // GetNumberOfKeyPackets returns the number of keys packets in this message. func (msg *PGPMessage) GetNumberOfKeyPackets() (int, error) { bytesReader := bytes.NewReader(msg.KeyPacket) packets := packet.NewReader(bytesReader) var keyPacketCount int for { p, err := packets.Next() if goerrors.Is(err, io.EOF) { break } if err != nil { return 0, err } switch p.(type) { case *packet.SymmetricKeyEncrypted, *packet.EncryptedKey: keyPacketCount += 1 } } return keyPacketCount, nil } // splitMessage splits the message into key and data packet(s). func (msg *PGPMessage) splitMessage() (*PGPMessage, error) { data := msg.DataPacket bytesReader := bytes.NewReader(data) packets := packet.NewReader(bytesReader) splitPoint := int64(0) Loop: for { p, err := packets.Next() if goerrors.Is(err, io.EOF) { break } if err != nil { return nil, err } switch p.(type) { case *packet.SymmetricKeyEncrypted, *packet.EncryptedKey: splitPoint = bytesReader.Size() - int64(bytesReader.Len()) case *packet.SymmetricallyEncrypted, *packet.AEADEncrypted: break Loop } } return &PGPMessage{ KeyPacket: data[:splitPoint], DataPacket: data[splitPoint:], }, nil } // Filename returns the filename of the literal metadata. func (msg *LiteralMetadata) Filename() string { if msg == nil { return "" } return msg.filename } // IsUtf8 returns whether the literal metadata is annotated with utf-8. func (msg *LiteralMetadata) IsUtf8() bool { if msg == nil { return false } return msg.isUTF8 } func (msg *LiteralMetadata) Time() int64 { if msg == nil { return 0 } return msg.ModTime } // PGPMessageBuffer implements the PGPSplitWriter interface func (mb *PGPMessageBuffer) Write(b []byte) (n int, err error) { return mb.data.Write(b) } // PGPMessage returns the PGPMessage extracted from the internal buffers. func (mb *PGPMessageBuffer) PGPMessage() *PGPMessage { return mb.PGPMessageWithOptions(false, false) } // PGPMessageWithOptions returns the PGPMessage extracted from the internal buffers. // The isPlain flag indicates wether the detached signature is encrypted or plaintext, if any. func (mb *PGPMessageBuffer) PGPMessageWithOptions(isPlain, omitArmorChecksum bool) *PGPMessage { var detachedSignature []byte if mb.signature.Len() > 0 { detachedSignature = mb.signature.Bytes() } if mb.key.Len() == 0 { pgpMessage := NewPGPMessage(mb.data.Bytes()) pgpMessage.DetachedSignature = detachedSignature return pgpMessage } return &PGPMessage{ KeyPacket: mb.key.Bytes(), DataPacket: mb.data.Bytes(), DetachedSignature: detachedSignature, detachedSignatureIsPlain: isPlain, omitArmorChecksum: omitArmorChecksum, } } func (mb *PGPMessageBuffer) Keys() Writer { return mb.key } func (mb *PGPMessageBuffer) Signature() Writer { return mb.signature } // ---- UTILS ----- // IsPGPMessage checks if data if has armored PGP message format. func IsPGPMessage(data string) bool { re := regexp.MustCompile("^-----BEGIN " + constants.PGPMessageHeader + "-----(?s:.+)-----END " + constants.PGPMessageHeader + "-----") return re.MatchString(data) } // SignatureKeyIDs returns the key identifiers of the keys that were used // to create the signatures. func SignatureKeyIDs(signature []byte) ([]uint64, bool) { packets := packet.NewReader(bytes.NewReader(signature)) var err error var ids []uint64 var onePassSignaturePacket *packet.OnePassSignature var signaturePacket *packet.Signature Loop: for { var p packet.Packet if p, err = packets.Next(); goerrors.Is(err, io.EOF) { break } switch p := p.(type) { case *packet.OnePassSignature: onePassSignaturePacket = p ids = append(ids, onePassSignaturePacket.KeyId) case *packet.Signature: signaturePacket = p if signaturePacket.IssuerKeyId != nil { ids = append(ids, *signaturePacket.IssuerKeyId) } case *packet.SymmetricallyEncrypted, *packet.AEADEncrypted, *packet.Compressed, *packet.LiteralData: break Loop } } if len(ids) > 0 { return ids, true } return ids, false } // SignatureHexKeyIDs returns the key identifiers of the keys that were used // to create the signatures in hexadecimal form. func SignatureHexKeyIDs(signature []byte) ([]string, bool) { return hexKeyIDs(SignatureKeyIDs(signature)) } func hexKeyIDs(keyIDs []uint64, ok bool) ([]string, bool) { hexIDs := make([]string, len(keyIDs)) for i, id := range keyIDs { hexIDs[i] = keyIDToHex(id) } return hexIDs, ok } // clone returns a clone of the byte slice. Internal function used to make sure // we don't retain a reference to external data. func clone(input []byte) []byte { data := make([]byte, len(input)) copy(data, input) return data } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/message_test.go000066400000000000000000000365031472137411600251360ustar00rootroot00000000000000package crypto import ( "bytes" "encoding/base64" "io" "os" "testing" "time" "github.com/ProtonMail/go-crypto/openpgp/packet" "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) func TestTextMessageEncryptionWithPassword(t *testing.T) { var message = []byte("The secret code is... 1, 2, 3, 4, 5") // Encrypt data with password encryptor, _ := testPGP.Encryption().Password(testSymmetricKey).New() encrypted, err := encryptor.Encrypt(message) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } packets := packet.NewReader(bytes.NewReader(encrypted.Bytes())) var foundSk bool for { var p packet.Packet var errEOF error if p, errEOF = packets.Next(); errors.Is(errEOF, io.EOF) { break } sessionKey, ok := p.(*packet.SymmetricKeyEncrypted) if ok { assert.Equal(t, sessionKey.CipherFunc, packet.CipherAES256) foundSk = true break } } if !foundSk { t.Fatal("Expect to found encrypted session key") } // Decrypt data with wrong password decryptorWrong, _ := testPGP.Decryption().Password([]byte("Wrong password")).New() _, err = decryptorWrong.Decrypt(encrypted.Bytes(), Bytes) assert.NotNil(t, err) // Decrypt data with the good password decryptor, _ := testPGP.Decryption().Password(testSymmetricKey).New() decrypted, err := decryptor.Decrypt(encrypted.Bytes(), Bytes) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, string(message), string(decrypted.Bytes())) } func TestBinaryMessageEncryptionWithPassword(t *testing.T) { binData, _ := base64.StdEncoding.DecodeString("ExXmnSiQ2QCey20YLH6qlLhkY3xnIBC1AwlIXwK/HvY=") var message = binData // Encrypt data with password encryptor, _ := testPGP.Encryption().Password(testSymmetricKey).New() encrypted, err := encryptor.Encrypt(message) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } // Decrypt data with wrong password decryptorWrong, _ := testPGP.Decryption().Password([]byte("Wrong password")).New() _, err = decryptorWrong.Decrypt(encrypted.Bytes(), Bytes) assert.NotNil(t, err) // Decrypt data with the good password decryptor, _ := testPGP.Decryption().Password(testSymmetricKey).New() decrypted, err := decryptor.Decrypt(encrypted.Bytes(), Bytes) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, message, decrypted.Bytes()) } func TestTextMixedMessageDecryptionWithPassword(t *testing.T) { encrypted, err := NewPGPMessageFromArmored(readTestFile("message_mixedPasswordPublic", false)) if err != nil { t.Fatal("Expected no error when unarmoring, got:", err) } // Decrypt data with the good password decryptor, _ := testPGP.Decryption().Password([]byte("pinata")).New() decrypted, err := decryptor.Decrypt(encrypted.Bytes(), Bytes) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } expected, err := os.ReadFile("testdata/message_mixedPasswordPublicExpected") if err != nil { panic(err) } assert.Exactly(t, expected, decrypted.Bytes()) } func TestTextMessageEncryption(t *testing.T) { var message = []byte( "The secret code is... 1, 2, 3, 4, 5. I repeat: the secret code is... 1, 2, 3, 4, 5", ) encryptor, _ := testPGP.Encryption().Recipients(keyRingTestPublic).New() ciphertext, err := encryptor.Encrypt(message) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } assert.Len(t, ciphertext.BinaryDataPacket(), 133) // Assert uncompressed encrypted body length decryptor, _ := testPGP.Decryption().DecryptionKeys(keyRingTestPrivate).New() decrypted, err := decryptor.Decrypt(ciphertext.Bytes(), Bytes) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, message, decrypted.Bytes()) } func TestTextMessageEncryptionWithTrailingSpaces(t *testing.T) { var original = "The secret code is... 1, 2, 3, 4, 5. I repeat: the secret code is... 1, 2, 3, 4, 5 " var message = []byte(original) encryptor, _ := testPGP.Encryption().Recipients(keyRingTestPublic).New() ciphertext, err := encryptor.Encrypt(message) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } decryptor, _ := testPGP.Decryption().DecryptionKeys(keyRingTestPrivate).New() decrypted, err := decryptor.Decrypt(ciphertext.Bytes(), Bytes) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, message, decrypted.Bytes()) } func TestTextMessageEncryptionWithNonCanonicalLinebreak(t *testing.T) { var original = "The secret code is... 1, 2, 3, 4, 5. I repeat: the secret code is... 1, 2, 3, 4, 5 \n \n" var message = []byte(original) encryptor, _ := testPGP.Encryption().Recipients(keyRingTestPublic).New() ciphertext, err := encryptor.Encrypt(message) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } decryptor, _ := testPGP.Decryption().DecryptionKeys(keyRingTestPrivate).New() decrypted, err := decryptor.Decrypt(ciphertext.Bytes(), Bytes) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, message, decrypted.Bytes()) } func TestIssue11(t *testing.T) { var issue11Password = []byte("1234") issue11Key, err := NewKeyFromArmored(readTestFile("issue11_privatekey", false)) if err != nil { t.Fatal("Expected no error while unarmoring private keyring, got:", err) } issue11Key, err = issue11Key.Unlock(issue11Password) if err != nil { t.Fatal("Expected no error while unlocking private key, got:", err) } issue11Keyring, err := NewKeyRing(issue11Key) if err != nil { t.Fatal("Expected no error while building private keyring, got:", err) } senderKey, err := NewKeyFromArmored(readTestFile("issue11_publickey", false)) if err != nil { t.Fatal("Expected no error while unarmoring public keyring, got:", err) } assert.Exactly(t, "643b3595e6ee4fdf", senderKey.GetHexKeyID()) senderKeyring, err := NewKeyRing(senderKey) if err != nil { t.Fatal("Expected no error while building public keyring, got:", err) } pgpMessage, err := NewPGPMessageFromArmored(readTestFile("issue11_message", false)) if err != nil { t.Fatal("Expected no error while reading ciphertext, got:", err) } decryptor, _ := testPGP.Decryption(). DecryptionKeys(issue11Keyring). VerificationKeys(senderKeyring). VerifyTime(1559655883).New() decrypted, err := decryptor.Decrypt(pgpMessage.Bytes(), Bytes) if err != nil { t.Fatal("Expected no error while decrypting/verifying, got:", err) } if err = decrypted.SignatureError(); err != nil { t.Fatal("Expected no error while decrypting/verifying, got:", err) } assert.Exactly(t, "message from sender", string(decrypted.Bytes())) } func TestDummy(t *testing.T) { dummyKey, err := NewKeyFromArmored(readTestFile("key_dummy", false)) if err != nil { t.Fatal("Expected no error while unarmoring public keyring, got:", err) } unlockedDummyKey, err := dummyKey.Unlock([]byte("golang")) if err != nil { t.Fatal("Expected no error while unlocking private key, got:", err) } _, err = testPGP.LockKey(unlockedDummyKey, []byte("golang")) if err != nil { t.Fatal("Expected no error while unlocking private key, got:", err) } dummyKeyRing, err := NewKeyRing(unlockedDummyKey) if err != nil { t.Fatal("Expected no error while building private keyring, got:", err) } var message = []byte( "The secret code is... 1, 2, 3, 4, 5. I repeat: the secret code is... 1, 2, 3, 4, 5", ) encryptor, _ := testPGP.Encryption().SignTime(1636644417).Recipients(dummyKeyRing).New() ciphertext, err := encryptor.Encrypt(message) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } assert.Len(t, ciphertext.BinaryDataPacket(), 133) // Assert uncompressed encrypted body length decryptor, _ := testPGP.Decryption().DecryptionKeys(dummyKeyRing).New() decrypted, err := decryptor.Decrypt(ciphertext.Bytes(), Bytes) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, message, decrypted.Bytes()) } func TestSignedMessageDecryption(t *testing.T) { pgpMessage, err := NewPGPMessageFromArmored(readTestFile("message_signed", false)) if err != nil { t.Fatal("Expected no error when unarmoring, got:", err) } decryptor, _ := testPGP.Decryption().DecryptionKeys(keyRingTestPrivate).New() decrypted, err := decryptor.Decrypt(pgpMessage.Bytes(), Bytes) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, readTestFile("message_plaintext", true), string(decrypted.Bytes())) } func TestSHA256SignedMessageDecryption(t *testing.T) { pgpMessage, err := NewPGPMessageFromArmored(readTestFile("message_sha256_signed", false)) if err != nil { t.Fatal("Expected no error when unarmoring, got:", err) } decryptor, _ := testPGP.Decryption(). DecryptionKeys(keyRingTestPrivate). VerificationKeys(keyRingTestPrivate). DisableVerifyTimeCheck(). New() decrypted, err := decryptor.Decrypt(pgpMessage.Bytes(), Bytes) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } if err = decrypted.SignatureError(); err != nil { t.Fatal("Expected no signature error when decrypting, got:", err) } assert.Exactly(t, readTestFile("message_plaintext", true), string(decrypted.Bytes())) } func TestSHA1SignedMessageDecryption(t *testing.T) { pgpMessage, err := NewPGPMessageFromArmored(readTestFile("message_sha1_signed", false)) if err != nil { t.Fatal("Expected no error when unarmoring, got:", err) } decryptor, _ := testPGP.Decryption(). DecryptionKeys(keyRingTestPrivate). VerificationKeys(keyRingTestPrivate). DisableVerifyTimeCheck(). New() decrypted, err := decryptor.Decrypt(pgpMessage.Bytes(), Bytes) if err != nil { t.Fatal("Expected no error, got: ", err) } if err = decrypted.SignatureError(); err == nil { t.Fatal("Expected verification error when decrypting") } if errStr := decrypted.SignatureError().Error(); errStr != "Signature Verification Error: Invalid signature caused by openpgp: invalid signature: insecure message hash algorithm: SHA-1" { t.Fatal("Expected verification error when decrypting, got:", errStr) } assert.Exactly(t, readTestFile("message_plaintext", true), string(decrypted.Bytes())) } func TestMultipleKeyMessageEncryption(t *testing.T) { var message = []byte("plain text") assert.Exactly(t, 3, len(keyRingTestMultiple.entities)) encryptor, _ := testPGP.Encryption().Recipients(keyRingTestMultiple).SigningKeys(keyRingTestPrivate).New() ciphertext, err := encryptor.Encrypt(message) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } // Test that ciphertext data contains three Encrypted Key Packets (tag 1) // followed by a single symmetrically encrypted data packet (tag 18) var p packet.Packet packets := packet.NewReader(bytes.NewReader(ciphertext.Bytes())) for i := 0; i < 3; i++ { if p, err = packets.Next(); err != nil { t.Fatal(err.Error()) } if _, ok := p.(*packet.EncryptedKey); !ok { t.Fatalf("Expected Encrypted Key packet, got %T", p) } } if p, err = packets.Next(); err != nil { t.Fatal(err.Error()) } if _, ok := p.(*packet.SymmetricallyEncrypted); !ok { t.Fatalf("Expected Symmetrically Encrypted Data packet, got %T", p) } // Decrypt message and verify correctness decryptor, _ := testPGP.Decryption(). DecryptionKeys(keyRingTestPrivate). VerificationKeys(keyRingTestPublic). New() decrypted, err := decryptor.Decrypt(ciphertext.Bytes(), Bytes) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } if err = decrypted.SignatureError(); err != nil { t.Fatal("Expected no signature error when decrypting, got:", err) } assert.Exactly(t, message, decrypted.Bytes()) } func TestMessageGetEncryptionKeyIDs(t *testing.T) { var message = []byte("plain text") assert.Exactly(t, 3, len(keyRingTestMultiple.entities)) encryptor, _ := testPGP.Encryption().Recipients(keyRingTestMultiple).SigningKeys(keyRingTestPrivate).New() ciphertext, err := encryptor.Encrypt(message) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } ids, ok := ciphertext.EncryptionKeyIDs() assert.Exactly(t, 3, len(ids)) assert.True(t, ok) encKey, ok := keyRingTestMultiple.entities[0].EncryptionKey(time.Now(), nil) assert.True(t, ok) assert.Exactly(t, encKey.PublicKey.KeyId, ids[0]) } func TestMessageGetHexGetEncryptionKeyIDs(t *testing.T) { ciphertext, err := NewPGPMessageFromArmored(readTestFile("message_multipleKeyID", false)) if err != nil { t.Fatal("Expected no error when reading message, got:", err) } ids, ok := ciphertext.HexEncryptionKeyIDs() assert.Exactly(t, 2, len(ids)) assert.True(t, ok) assert.Exactly(t, "76ad736fa7e0e83c", ids[0]) assert.Exactly(t, "0f65b7ae456a9ceb", ids[1]) } func TestMessageGetSignatureKeyIDs(t *testing.T) { var message = []byte("plain text") signer, _ := testPGP.Sign().SigningKeys(keyRingTestPrivate).Detached().New() signature, err := signer.Sign(message, Bytes) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } ids, ok := SignatureKeyIDs(signature) assert.Exactly(t, 1, len(ids)) assert.True(t, ok) signingKey, ok := keyRingTestPrivate.entities[0].SigningKey(time.Now(), nil) assert.True(t, ok) assert.Exactly(t, signingKey.PublicKey.KeyId, ids[0]) } func TestMessageGetHexSignatureKeyIDs(t *testing.T) { ciphertext, err := NewPGPMessageFromArmored(readTestFile("message_plainSignature", false)) if err != nil { t.Fatal("Expected no error when reading message, got:", err) } ids, ok := ciphertext.HexSignatureKeyIDs() assert.Exactly(t, 2, len(ids)) assert.True(t, ok) assert.Exactly(t, "3eb6259edf21df24", ids[0]) assert.Exactly(t, "d05b722681936ad0", ids[1]) } func TestMessageGetArmoredWithCustomHeaders(t *testing.T) { var message = []byte("plain text") encryptor, _ := testPGP.Encryption().Recipients(keyRingTestPublic).SigningKeys(keyRingTestPrivate).New() ciphertext, err := encryptor.Encrypt(message) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } comment := "User-defined comment" version := "User-defined version" armored, err := ciphertext.ArmorWithCustomHeaders(comment, version) if err != nil { t.Fatal("Could not armor the ciphertext:", err) } assert.Contains(t, armored, "Comment: "+comment) assert.Contains(t, armored, "Version: "+version) } func TestMessageGetArmoredWithEmptyHeaders(t *testing.T) { var message = []byte("plain text") encryptor, _ := testPGP.Encryption().Recipients(keyRingTestPublic).SigningKeys(keyRingTestPrivate).New() ciphertext, err := encryptor.Encrypt(message) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } comment := "" version := "" armored, err := ciphertext.ArmorWithCustomHeaders(comment, version) if err != nil { t.Fatal("Could not armor the ciphertext:", err) } assert.NotContains(t, armored, "Version") assert.NotContains(t, armored, "Comment") } func TestPGPSplitMessageFromArmoredWithAEAD(t *testing.T) { var message = `-----BEGIN PGP MESSAGE----- hF4DJDxTg/yg6TkSAQdA3Ogzuxwz7IdSRCh81gdYuB0bKqkYDs7EksOkYJ7eUnMw FsRNg+X3KbCj9j747An4J7V8trghOIN00dlpuR77wELS79XHoP55qmyVyPzmTXdx 1F8BCQIQyGCAxAA1ppydoBVp7ithTEl2bU72tbOsLCFY8TBamG6t3jfqJpO2lz+G M0xNgvwIDrAQsN35VGw72I/FvWJ0VG3rpBKgFp5nPK0NblRomXTRRfoNgSoVUcxU vA== =YNf2 -----END PGP MESSAGE----- ` msg, err := NewPGPMessageFromArmored(message) if err != nil { t.Errorf("Couldn't parse split message: %v", err) } if msg.KeyPacket == nil { t.Error("Key packet was nil") } if msg.DataPacket == nil { t.Error("Data packet was nil") } } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/sessionkey.go000066400000000000000000000116261472137411600246460ustar00rootroot00000000000000package crypto import ( "encoding/base64" "fmt" "io" "github.com/ProtonMail/gopenpgp/v3/constants" "github.com/pkg/errors" pgpErrors "github.com/ProtonMail/go-crypto/openpgp/errors" "github.com/ProtonMail/go-crypto/openpgp/packet" ) // SessionKey stores a decrypted session key. type SessionKey struct { // Key defines the decrypted binary session key. Key []byte // Algo defines the symmetric encryption algorithm used with this key. // Only present if the key was not parsed from a v6 packet. Algo string // v6 is a flag to indicate that the session key was parsed from a v6 PKESK or SKESK packet v6 bool } var symKeyAlgos = map[string]packet.CipherFunction{ constants.ThreeDES: packet.Cipher3DES, constants.TripleDES: packet.Cipher3DES, constants.CAST5: packet.CipherCAST5, constants.AES128: packet.CipherAES128, constants.AES192: packet.CipherAES192, constants.AES256: packet.CipherAES256, } var algosToSymKey = map[packet.CipherFunction]string{ packet.Cipher3DES: constants.TripleDES, packet.CipherCAST5: constants.CAST5, packet.CipherAES128: constants.AES128, packet.CipherAES192: constants.AES192, packet.CipherAES256: constants.AES256, } type checkReader struct { decrypted io.ReadCloser body io.Reader } func (cr checkReader) Read(buf []byte) (int, error) { n, sensitiveParsingError := cr.body.Read(buf) if sensitiveParsingError == io.EOF { mdcErr := cr.decrypted.Close() if mdcErr != nil { return n, mdcErr } return n, io.EOF } if sensitiveParsingError != nil { return n, pgpErrors.StructuralError("parsing error") } return n, nil } // GetCipherFunc returns the cipher function corresponding to the algorithm used // with this SessionKey. // Not supported in go-mobile clients use sk.GetCipherFuncInt instead. func (sk *SessionKey) GetCipherFunc() (packet.CipherFunction, error) { if sk.v6 { return 0, errors.New("gopenpgp: no cipher function available for a v6 session key") } cf, ok := symKeyAlgos[sk.Algo] if !ok { return cf, errors.New("gopenpgp: unsupported cipher function: " + sk.Algo) } return cf, nil } // GetCipherFuncInt returns the cipher function as int8 corresponding to the algorithm used // with this SessionKey. // The int8 type is used for go-mobile clients, see constant.Cipher... func (sk *SessionKey) GetCipherFuncInt() (int8, error) { cipherFunc, err := sk.GetCipherFunc() return int8(cipherFunc), err } // GetBase64Key returns the session key as base64 encoded string. func (sk *SessionKey) GetBase64Key() string { return base64.StdEncoding.EncodeToString(sk.Key) } // RandomToken generates a random token with the specified key size. func RandomToken(size int) ([]byte, error) { config := &packet.Config{DefaultCipher: packet.CipherAES256} symKey := make([]byte, size) if _, err := io.ReadFull(config.Random(), symKey); err != nil { return nil, errors.Wrap(err, "gopenpgp: error in generating random token") } return symKey, nil } // GenerateSessionKeyAlgo generates a random key of the correct length for the // specified algorithm. func GenerateSessionKeyAlgo(algo string) (sk *SessionKey, err error) { cf, ok := symKeyAlgos[algo] if !ok { return nil, errors.New("gopenpgp: unknown symmetric key generation algorithm") } r, err := RandomToken(cf.KeySize()) if err != nil { return nil, err } sk = &SessionKey{ Key: r, Algo: algo, } return sk, nil } // GenerateSessionKey generates a random key for the default cipher. func generateSessionKey(config *packet.Config) (*SessionKey, error) { cf, ok := algosToSymKey[config.DefaultCipher] if !ok { return nil, errors.New("gopenpgp: unsupported cipher function") } return GenerateSessionKeyAlgo(cf) } // NewSessionKeyFromToken creates a SessionKey struct with the given token and algorithm. // Clones the token for compatibility with go-mobile. func NewSessionKeyFromToken(token []byte, algo string) *SessionKey { return &SessionKey{ Key: clone(token), Algo: algo, } } func newSessionKeyFromEncrypted(ek *packet.EncryptedKey) (*SessionKey, error) { var algo string for k, v := range symKeyAlgos { if v == ek.CipherFunc { algo = k break } } if algo == "" && ek.Version < 6 { return nil, fmt.Errorf("gopenpgp: unsupported cipher function: %v", ek.CipherFunc) } sk := &SessionKey{ Key: ek.Key, Algo: algo, v6: ek.Version == 6, } if ek.Version < 6 { if err := sk.checkSize(); err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to decrypt session key") } } return sk, nil } func (sk *SessionKey) checkSize() error { if sk.v6 { // cannot check size return errors.New("unknown key size") } cf, ok := symKeyAlgos[sk.Algo] if !ok { return errors.New("unknown symmetric key algorithm") } if cf.KeySize() != len(sk.Key) { return errors.New("wrong session key size") } return nil } func getAlgo(cipher packet.CipherFunction) string { algo := "" for k, v := range symKeyAlgos { if v == cipher { algo = k break } } return algo } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/sessionkey_test.go000066400000000000000000000304231472137411600257010ustar00rootroot00000000000000package crypto import ( "encoding/base64" "encoding/hex" "os" "testing" "github.com/ProtonMail/gopenpgp/v3/constants" "github.com/stretchr/testify/assert" ) var testSessionKey *SessionKey func init() { var err error testSessionKey, err = GenerateSessionKeyAlgo("aes256") if err != nil { panic("Expected no error while generating random session key with aes256, got:" + err.Error()) } } func TestRandomToken(t *testing.T) { token40, err := RandomToken(40) if err != nil { t.Fatal("Expected no error while generating random token, got:", err) } assert.Len(t, token40, 40) } func TestGenerateSessionKey(t *testing.T) { assert.Len(t, testSessionKey.Key, 32) } func TestAsymmetricKeyPacket(t *testing.T) { encHandle, _ := testPGP.Encryption().Recipients(keyRingTestPublic).New() keyPacket, err := encHandle.EncryptSessionKey(testSessionKey) if err != nil { t.Fatal("Expected no error while generating key packet, got:", err) } // Password defined in keyring_test decHandle, _ := testPGP.Decryption().DecryptionKeys(keyRingTestPrivate).New() outputSymmetricKey, err := decHandle.DecryptSessionKey(keyPacket) if err != nil { t.Fatal("Expected no error while decrypting key packet, got:", err) } assert.Exactly(t, testSessionKey, outputSymmetricKey) } func TestMultipleAsymmetricKeyPacket(t *testing.T) { encHandle, _ := testPGP.Encryption().Recipients(keyRingTestMultiple).New() keyPacket, err := encHandle.EncryptSessionKey(testSessionKey) if err != nil { t.Fatal("Expected no error while generating key packet, got:", err) } // Password defined in keyring_test decHandle, _ := testPGP.Decryption().DecryptionKeys(keyRingTestPrivate).New() outputSymmetricKey, err := decHandle.DecryptSessionKey(keyPacket) if err != nil { t.Fatal("Expected no error while decrypting key packet, got:", err) } assert.Exactly(t, testSessionKey, outputSymmetricKey) } func TestSymmetricKeyPacket(t *testing.T) { password := []byte("I like encryption") encHandle, _ := testPGP.Encryption().Password(password).New() keyPacket, err := encHandle.EncryptSessionKey(testSessionKey) if err != nil { t.Fatal("Expected no error while generating key packet, got:", err) } decHandle, _ := testPGP.Decryption().Password([]byte("Wrong password")).New() wrongSymmetricKey, err := decHandle.DecryptSessionKey(keyPacket) if err != nil { assert.EqualError(t, err, "gopenpgp: unable to decrypt any packet") } else { assert.NotEqual(t, testSessionKey, wrongSymmetricKey) } decHandle, _ = testPGP.Decryption().Password(password).New() outputSymmetricKey, err := decHandle.DecryptSessionKey(keyPacket) if err != nil { t.Fatal("Expected no error while decrypting key packet, got:", err) } assert.Exactly(t, testSessionKey, outputSymmetricKey) } func TestSymmetricKeyPacketWrongSize(t *testing.T) { r, err := RandomToken(symKeyAlgos[constants.AES256].KeySize()) if err != nil { t.Fatal("Expected no error while generating session key, got:", err) } sk := &SessionKey{ Key: r, Algo: constants.AES128, } password := []byte("I like encryption") _, err = encryptSessionKeyWithPassword(sk, password, testPGP.profile.EncryptionConfig()) if err == nil { t.Fatal("Expected error while generating key packet with wrong sized key") } } func TestDataPacketEncryption(t *testing.T) { var message = []byte( "The secret code is... 1, 2, 3, 4, 5. I repeat: the secret code is... 1, 2, 3, 4, 5", ) // Encrypt data with session key encryptor, _ := testPGP.Encryption().SessionKey(testSessionKey).New() pgpMessage, err := encryptor.Encrypt(message) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } assert.Len(t, pgpMessage.Bytes(), 133) // Assert uncompressed encrypted body length // Decrypt data with wrong session key wrongKey := &SessionKey{ Key: []byte("wrong pass"), Algo: constants.AES256, } decryptor, _ := testPGP.Decryption().SessionKey(wrongKey).New() _, err = decryptor.Decrypt(pgpMessage.BinaryDataPacket(), Bytes) assert.NotNil(t, err) // Decrypt data with the good session key decryptor, _ = testPGP.Decryption().SessionKey(testSessionKey).New() decrypted, err := decryptor.Decrypt(pgpMessage.BinaryDataPacket(), Bytes) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, message, decrypted.Bytes()) // Encrypt session key assert.Exactly(t, 3, len(keyRingTestMultiple.entities)) encryptor, _ = testPGP.Encryption().Recipients(keyRingTestMultiple).New() keyPackets, err := encryptor.EncryptSessionKey(testSessionKey) if err != nil { t.Fatal("Unable to encrypt key packet, got:", err) } // Join key packet and data packet in single message pgpMessage.KeyPacket = keyPackets // Armor and un-armor message. In alternative it can also be done with NewPgpMessage(splitMessage.GetBinary()) armored, err := pgpMessage.Armor() if err != nil { t.Fatal("Unable to armor split message, got:", err) } pgpMessage, err = NewPGPMessageFromArmored(armored) if err != nil { t.Fatal("Unable to unarmor pgp message, got:", err) } ids, ok := pgpMessage.EncryptionKeyIDs() assert.True(t, ok) assert.Exactly(t, 3, len(ids)) // Test if final decryption succeeds decryptor, _ = testPGP.Decryption().DecryptionKeys(keyRingTestPrivate).New() finalMessageResult, err := decryptor.Decrypt(pgpMessage.Bytes(), Bytes) if err != nil { t.Fatal("Unable to decrypt joined keypacket and datapacket, got:", err) } assert.Exactly(t, message, finalMessageResult.Bytes()) } func TestSessionKeyClear(t *testing.T) { testSessionKey.Clear() assertMemCleared(t, testSessionKey.Key) } func TestAEADDataPacketDecryption(t *testing.T) { pgpMessageData, err := os.ReadFile("testdata/gpg2.3-aead-pgp-message.pgp") if err != nil { t.Fatal("Expected no error when reading message data, got:", err) } pgpMessage := NewPGPMessage(pgpMessageData) aeadKey, err := NewKeyFromArmored(readTestFile("gpg2.3-aead-test-key.asc", false)) if err != nil { t.Fatal("Expected no error when unarmoring key, got:", err) } aeadKeyUnlocked, err := aeadKey.Unlock([]byte("test")) if err != nil { t.Fatal("Expected no error when unlocking, got:", err) } kR, err := NewKeyRing(aeadKeyUnlocked) if err != nil { t.Fatal("Expected no error when creating the keyring, got:", err) } defer kR.ClearPrivateParams() decryptor, _ := testPGP.Decryption().DecryptionKeys(kR).New() sessionKey, err := decryptor.DecryptSessionKey(pgpMessage.BinaryKeyPacket()) if err != nil { t.Fatal("Expected no error when decrypting session key, got:", err) } decryptor, _ = testPGP.Decryption().SessionKey(sessionKey).New() decrypted, err := decryptor.Decrypt(pgpMessage.BinaryDataPacket(), Bytes) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, "hello world\n", string(decrypted.Bytes())) } func TestDataPacketEncryptionAndSignature(t *testing.T) { var message = []byte( "The secret code is... 1, 2, 3, 4, 5. I repeat: the secret code is... 1, 2, 3, 4, 5", ) // Encrypt data with session key encryptor, _ := testPGP.Encryption().SessionKey(testSessionKey).SigningKeys(keyRingTestPrivate).New() pgpMessage, err := encryptor.Encrypt(message) if err != nil { t.Fatal("Expected no error when encrypting and signing, got:", err) } // Decrypt data with wrong session key wrongKey := &SessionKey{ Key: []byte("wrong pass"), Algo: constants.AES256, } decryptor, _ := testPGP.Decryption().SessionKey(wrongKey).New() _, err = decryptor.Decrypt(pgpMessage.BinaryDataPacket(), Bytes) assert.NotNil(t, err) // Decrypt data with the good session key decryptor, _ = testPGP.Decryption().SessionKey(testSessionKey).New() decrypted, err := decryptor.Decrypt(pgpMessage.BinaryDataPacket(), Bytes) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, message, decrypted.Bytes()) // Decrypt & verify data with the good session key but bad keyring ecKeyRing, err := NewKeyRing(keyTestEC) if err != nil { t.Fatal("Unable to generate EC keyring, got:", err) } decryptor, _ = testPGP.Decryption().SessionKey(testSessionKey).VerificationKeys(ecKeyRing).New() decrypted, err = decryptor.Decrypt(pgpMessage.BinaryDataPacket(), Bytes) if err != nil { t.Fatal("Wrong error returned for verification failure", err) } if err = decrypted.SignatureError(); err == nil { t.Fatal("No error returned for verification failure", err) } // Decrypt & verify data with the good session key and keyring decryptor, _ = testPGP.Decryption().SessionKey(testSessionKey).VerificationKeys(keyRingTestPublic).New() decrypted, err = decryptor.Decrypt(pgpMessage.BinaryDataPacket(), Bytes) if err != nil { t.Fatal("Expected no error when decrypting & verifying, got:", err) } if err = decrypted.SignatureError(); err != nil { t.Fatal("Expected no error when decrypting & verifying, got:", err) } assert.Exactly(t, message, decrypted.Bytes()) // Encrypt session key assert.Exactly(t, 3, len(keyRingTestMultiple.entities)) encryptor, _ = testPGP.Encryption().Recipients(keyRingTestMultiple).New() keyPacket, err := encryptor.EncryptSessionKey(testSessionKey) if err != nil { t.Fatal("Unable to encrypt key packet, got:", err) } // Join key packet and data packet in single message pgpMessage.KeyPacket = keyPacket // Armor and un-armor message. In alternative it can also be done with NewPgpMessage(splitMessage.GetBinary()) armored, err := pgpMessage.Armor() if err != nil { t.Fatal("Unable to armor split message, got:", err) } pgpMessage, err = NewPGPMessageFromArmored(armored) if err != nil { t.Fatal("Unable to unarmor pgp message, got:", err) } ids, ok := pgpMessage.EncryptionKeyIDs() assert.True(t, ok) assert.Exactly(t, 3, len(ids)) // Test if final decryption & verification succeeds decryptor, _ = testPGP.Decryption().DecryptionKeys(keyRingTestPrivate).VerificationKeys(keyRingTestPublic).New() finalMessage, err := decryptor.Decrypt(pgpMessage.Bytes(), Bytes) if err != nil { t.Fatal("Unable to decrypt and verify joined keypacket and datapacket, got:", err) } if err = finalMessage.SignatureError(); err != nil { t.Fatal("Unexpected verification error for joined keypacket and datapacket, got:", err) } assert.Exactly(t, message, finalMessage.Bytes()) } func TestDataPacketDecryption(t *testing.T) { pgpMessage, err := NewPGPMessageFromArmored(readTestFile("message_signed", false)) if err != nil { t.Fatal("Expected no error when unarmoring, got:", err) } decryptor, _ := testPGP.Decryption().DecryptionKeys(keyRingTestPrivate).New() sessionKey, err := decryptor.DecryptSessionKey(pgpMessage.BinaryKeyPacket()) if err != nil { t.Fatal("Expected no error when decrypting session key, got:", err) } decryptor, _ = testPGP.Decryption().SessionKey(sessionKey).New() decrypted, err := decryptor.Decrypt(pgpMessage.BinaryDataPacket(), Bytes) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, readTestFile("message_plaintext", true), string(decrypted.Bytes())) } func TestMDCFailDecryption(t *testing.T) { pgpMessage, err := NewPGPMessageFromArmored(readTestFile("message_badmdc", false)) if err != nil { t.Fatal("Expected no error when unarmoring, got:", err) } sk, _ := hex.DecodeString("F76D3236E4F8A38785C50BDE7167475E95360BCE67A952710F6C16F18BB0655E") sessionKey := NewSessionKeyFromToken(sk, "aes256") decryptor, _ := testPGP.Decryption().SessionKey(sessionKey).New() _, err = decryptor.Decrypt(pgpMessage.BinaryDataPacket(), Bytes) assert.NotNil(t, err) } func TestAsymmetricKeyPacketDecryptionFailure(t *testing.T) { passphrase := []byte("passphrase") keyPacket, err := base64.StdEncoding.DecodeString(readTestFile("sessionkey_packet", false)) if err != nil { t.Error("Expected no error while decoding key packet, got:" + err.Error()) } pk, err := NewKeyFromArmored(readTestFile("sessionkey_key", false)) if err != nil { t.Error("Expected no error while unarmoring private key, got:" + err.Error()) } uk, err := pk.Unlock(passphrase) if err != nil { t.Error("Expected no error while unlocking private key, got:" + err.Error()) } defer uk.ClearPrivateParams() ukr, err := NewKeyRing(uk) if err != nil { t.Error("Expected no error while building private keyring, got:" + err.Error()) } decryptor, _ := testPGP.Decryption().DecryptionKeys(ukr).New() _, err = decryptor.DecryptSessionKey(keyPacket) assert.Error(t, err, "gopenpgp: unable to decrypt session key") } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/sign.go000066400000000000000000000024161472137411600234070ustar00rootroot00000000000000package crypto import "github.com/ProtonMail/go-crypto/openpgp/packet" type SignProfile interface { SignConfig() *packet.Config } // PGPSign is an interface for creating signature messages with GopenPGP. type PGPSign interface { // SigningWriter returns a wrapper around underlying output Writer, // such that any write-operation via the wrapper results in a write to a detached or inline signature message. // The encoding argument defines the output encoding, i.e., Bytes or Armored // Once close is called on the returned WriteCloser the final signature is written to the output. // Thus, the returned WriteCloser must be closed after the plaintext has been written. SigningWriter(output Writer, encoding int8) (WriteCloser, error) // Sign creates a detached or inline signature from the provided byte slice. // The encoding argument defines the output encoding, i.e., Bytes or Armored Sign(message []byte, encoding int8) ([]byte, error) // SignCleartext produces an armored cleartext message according to the specification. // Returns an armored message even if the PGPSign is not configured for armored output. SignCleartext(message []byte) ([]byte, error) // ClearPrivateParams clears all secret key material contained in the PGPSign from memory, ClearPrivateParams() } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/sign_handle.go000066400000000000000000000144531472137411600247260ustar00rootroot00000000000000package crypto import ( "bytes" "io" "time" "unicode/utf8" "github.com/ProtonMail/go-crypto/openpgp/armor" "github.com/ProtonMail/go-crypto/openpgp/clearsign" "github.com/ProtonMail/go-crypto/openpgp/packet" openpgp "github.com/ProtonMail/go-crypto/openpgp/v2" "github.com/ProtonMail/gopenpgp/v3/constants" "github.com/ProtonMail/gopenpgp/v3/internal" "github.com/pkg/errors" ) type signatureHandle struct { SignKeyRing *KeyRing SignContext *SigningContext IsUTF8 bool Detached bool ArmorHeaders map[string]string profile SignProfile clock Clock } // --- Default signature handle to build from func defaultSignatureHandle(profile SignProfile, clock Clock) *signatureHandle { return &signatureHandle{ profile: profile, ArmorHeaders: internal.ArmorHeaders, clock: clock, } } // --- Implements the signature handle methods // SigningWriter returns a wrapper around underlying output Writer, // such that any write-operation via the wrapper results in a write to a detached or inline signature message. // The encoding argument defines the output encoding, i.e., Bytes or Armored // Once close is called on the returned WriteCloser the final signature is written to the output. // Thus, the returned WriteCloser must be closed after the plaintext has been written. func (sh *signatureHandle) SigningWriter(outputWriter Writer, encoding int8) (messageWriter WriteCloser, err error) { var armorWriter WriteCloser armorOutput := armorOutput(encoding) if armorOutput { writeChecksum := sh.armorChecksumRequired() var err error header := constants.PGPMessageHeader if sh.Detached { header = constants.PGPSignatureHeader } armorWriter, err = armor.EncodeWithChecksumOption(outputWriter, header, sh.ArmorHeaders, writeChecksum) if err != nil { return nil, err } outputWriter = armorWriter } if sh.Detached { // Detached signature messageWriter, err = signMessageDetachedWriter( sh.SignKeyRing, outputWriter, sh.IsUTF8, sh.SignContext, sh.clock, sh.profile.SignConfig(), ) } else { // Inline signature messageWriter, err = sh.signingWriter(outputWriter, nil) } if err != nil { return nil, err } if armorOutput { // Ensure that close is called on the armor writer for the armor suffix messageWriter = &armoredWriteCloser{ armorWriter: armorWriter, messageWriter: messageWriter, } } if sh.IsUTF8 { messageWriter = internal.NewUtf8CheckWriteCloser( openpgp.NewCanonicalTextWriteCloser(messageWriter), ) } return messageWriter, nil } // Sign creates a detached or inline signature from the provided byte slice. // The encoding argument defines the output encoding, i.e., Bytes or Armored. func (sh *signatureHandle) Sign(message []byte, encoding int8) ([]byte, error) { var writer bytes.Buffer ptWriter, err := sh.SigningWriter(&writer, encoding) if err != nil { return nil, err } _, err = ptWriter.Write(message) if err != nil { return nil, err } err = ptWriter.Close() if err != nil { return nil, err } return writer.Bytes(), nil } // SignCleartext produces an armored cleartext message according to the specification. // Returns an armored message even if the PGPSign is not configured for armored output. func (sh *signatureHandle) SignCleartext(message []byte) ([]byte, error) { return sh.signCleartext(message) } // ClearPrivateParams clears all secret key material contained in the PGPSign from memory. func (sh *signatureHandle) ClearPrivateParams() { if sh.SignKeyRing != nil { sh.SignKeyRing.ClearPrivateParams() } } // --- Private signature handle logic func (sh *signatureHandle) validate() error { if sh.SignKeyRing == nil { return errors.New("gopenpgp: no signing key provided") } return nil } func (sh *signatureHandle) armorChecksumRequired() bool { if !constants.ArmorChecksumEnabled { // If the default behavior is no checksum, we can ignore // the logic for the RFC9580 check. return false } if sh.SignKeyRing == nil { return true } for _, signer := range sh.SignKeyRing.entities { if signer.PrimaryKey.Version != 6 { return true } } return false } func (sh *signatureHandle) signCleartext(message []byte) ([]byte, error) { config := sh.profile.SignConfig() config.Time = NewConstantClock(sh.clock().Unix()) var buffer bytes.Buffer var privateKeys []*packet.PrivateKey if !utf8.Valid(message) { return nil, internal.ErrIncorrectUtf8 } for _, entity := range sh.SignKeyRing.entities { key, ok := entity.SigningKey(config.Now(), config) if ok && key.PrivateKey != nil && !key.PrivateKey.Encrypted { privateKeys = append(privateKeys, key.PrivateKey) } else { return nil, errors.New("gopenpgp: no signing key found for entity") } } writer, err := clearsign.EncodeMultiWithHeader(&buffer, privateKeys, config, sh.ArmorHeaders) if err != nil { return nil, err } _, err = writer.Write(message) if err != nil { return nil, err } err = writer.Close() if err != nil { return nil, err } return buffer.Bytes(), nil } func (sh *signatureHandle) signingWriter(messageWriter Writer, literalData *LiteralMetadata) (WriteCloser, error) { config := sh.profile.SignConfig() config.Time = NewConstantClock(sh.clock().Unix()) signers, err := sh.SignKeyRing.signingEntities() if err != nil { return nil, err } hints := &openpgp.FileHints{ FileName: literalData.Filename(), IsUTF8: sh.IsUTF8, ModTime: time.Unix(literalData.Time(), 0), } if sh.SignContext != nil { config.SignatureNotations = append(config.SignatureNotations, sh.SignContext.getNotation()) } return openpgp.SignWithParams(messageWriter, signers, &openpgp.SignParams{ Hints: hints, TextSig: sh.IsUTF8, Config: config, }) } func signMessageDetachedWriter( signKeyRing *KeyRing, outputWriter io.Writer, isUTF8 bool, context *SigningContext, clock Clock, config *packet.Config, ) (ptWriter io.WriteCloser, err error) { config.Time = NewConstantClock(clock().Unix()) signers, err := signKeyRing.signingEntities() if err != nil { return nil, err } if context != nil { config.SignatureNotations = append(config.SignatureNotations, context.getNotation()) } ptWriter, err = openpgp.DetachSignWriter(outputWriter, signers, &openpgp.SignParams{ TextSig: isUTF8, Config: config, }) if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in signing") } return ptWriter, nil } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/sign_handle_builder.go000066400000000000000000000060731472137411600264330ustar00rootroot00000000000000package crypto // SignHandleBuilder allows to configure a sign handle // to sign data with OpenPGP. type SignHandleBuilder struct { handle *signatureHandle defaultClock Clock err error } func newSignHandleBuilder(profile SignProfile, clock Clock) *SignHandleBuilder { return &SignHandleBuilder{ handle: defaultSignatureHandle(profile, clock), defaultClock: clock, } } // SigningKey sets the signing key that is used to create signature of the message. func (shb *SignHandleBuilder) SigningKey(key *Key) *SignHandleBuilder { var err error if shb.handle.SignKeyRing == nil { shb.handle.SignKeyRing, err = NewKeyRing(key) } else { err = shb.handle.SignKeyRing.AddKey(key) } shb.err = err return shb } // SigningKeys sets the signing keys that are used to create signature of the message. func (shb *SignHandleBuilder) SigningKeys(signingKeys *KeyRing) *SignHandleBuilder { shb.handle.SignKeyRing = signingKeys return shb } // SigningContext provides a signing context for the signature in the message. // Triggers that each signature includes the sining context. func (shb *SignHandleBuilder) SigningContext(signingContext *SigningContext) *SignHandleBuilder { shb.handle.SignContext = signingContext return shb } // Detached indicates if a detached signature should be produced. // The sign output will be a detached signature message without the data included. func (shb *SignHandleBuilder) Detached() *SignHandleBuilder { shb.handle.Detached = true return shb } // ArmorHeader indicates that the produced signature should be armored // with the given version and comment as header. // Note that this option only affects the method SignHandle.SigningWriter // and the headers in SignHandle.SignCleartext. func (shb *SignHandleBuilder) ArmorHeader(version, comment string) *SignHandleBuilder { if shb.handle.ArmorHeaders == nil { shb.handle.ArmorHeaders = make(map[string]string) } shb.handle.ArmorHeaders["Version"] = version shb.handle.ArmorHeaders["Comment"] = comment return shb } // Utf8 indicates if the plaintext should be signed with a text type // signature. If set, the plaintext is signed after // canonicalising the line endings. func (shb *SignHandleBuilder) Utf8() *SignHandleBuilder { shb.handle.IsUTF8 = true return shb } // SignTime sets the internal clock to always return // the supplied unix time for signing instead of the device time. func (shb *SignHandleBuilder) SignTime(unixTime int64) *SignHandleBuilder { shb.handle.clock = NewConstantClock(unixTime) return shb } // New creates a SignHandle and checks that the given // combination of parameters is valid. If the parameters are invalid // an error is returned. func (shb *SignHandleBuilder) New() (PGPSign, error) { if shb.err != nil { return nil, shb.err } shb.err = shb.handle.validate() if shb.err != nil { return nil, shb.err } handle := shb.handle shb.handle = defaultSignatureHandle(shb.handle.profile, shb.defaultClock) return handle, nil } // Error returns any errors that occurred within the builder. func (shb *SignHandleBuilder) Error() error { return shb.err } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/sign_verify_test.go000066400000000000000000000260571472137411600260410ustar00rootroot00000000000000package crypto import ( "bytes" "testing" "github.com/stretchr/testify/assert" ) const messageToSign = "Hello World!" const messageCleartext = " Signed message\n \n " const expectedMessageCleartext = " Signed message\n\n" func TestSignVerifyStream(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { signer, _ := material.pgp.Sign(). SigningKeys(material.keyRingTestPrivate). New() verifier, _ := material.pgp.Verify(). VerificationKeys(material.keyRingTestPublic). New() testSignVerifyStream(t, signer, verifier, Bytes, len(material.keyRingTestPrivate.entities)) }) } } func TestSignVerifyStreamContext(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { signer, _ := material.pgp.Sign(). SigningKeys(material.keyRingTestPrivate). SigningContext(NewSigningContext(testContext, true)). New() verifier, _ := material.pgp.Verify(). VerificationKeys(material.keyRingTestPublic). VerificationContext(NewVerificationContext(testContext, true, 0)). New() testSignVerifyStream(t, signer, verifier, Bytes, len(material.keyRingTestPrivate.entities)) }) } } func TestSignVerifyStreamArmor(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { signer, _ := material.pgp.Sign(). SigningKeys(material.keyRingTestPrivate). New() verifier, _ := material.pgp.Verify(). VerificationKeys(material.keyRingTestPublic). New() testSignVerifyStream(t, signer, verifier, Armor, len(material.keyRingTestPrivate.entities)) }) } } func TestSignVerify(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { signer, _ := material.pgp.Sign(). SigningKeys(material.keyRingTestPrivate). New() verifier, _ := material.pgp.Verify(). VerificationKeys(material.keyRingTestPublic). New() testSignVerify(t, signer, verifier, false, Bytes, len(material.keyRingTestPrivate.entities)) }) } } func TestSignVerifyUtf8(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { signer, _ := material.pgp.Sign(). SigningKeys(material.keyRingTestPrivate). Utf8(). New() verifier, _ := material.pgp.Verify(). VerificationKeys(material.keyRingTestPublic). Utf8(). New() testSignVerify(t, signer, verifier, false, Bytes, len(material.keyRingTestPrivate.entities)) }) } } func TestSignVerifyDetached(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { signer, _ := material.pgp.Sign(). SigningKeys(material.keyRingTestPrivate). Detached(). New() verifier, _ := material.pgp.Verify(). VerificationKeys(material.keyRingTestPublic). New() testSignVerify(t, signer, verifier, true, Bytes, len(material.keyRingTestPrivate.entities)) }) } } func TestSignVerifyDetachedUtf8(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { signer, _ := material.pgp.Sign(). SigningKeys(material.keyRingTestPrivate). Detached(). Utf8(). New() verifier, _ := material.pgp.Verify(). VerificationKeys(material.keyRingTestPublic). Utf8(). New() testSignVerify(t, signer, verifier, true, Bytes, len(material.keyRingTestPrivate.entities)) }) } } func TestSignVerifyStreamDetached(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { signer, _ := material.pgp.Sign(). SigningKeys(material.keyRingTestPrivate). Detached(). New() verifier, _ := material.pgp.Verify(). VerificationKeys(material.keyRingTestPublic). New() testSignVerifyDetachedStream(t, signer, verifier, Bytes, len(material.keyRingTestPrivate.entities)) }) } } func TestSignVerifyStreamDetachedContext(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { signer, _ := material.pgp.Sign(). SigningKeys(material.keyRingTestPrivate). Detached(). SigningContext(NewSigningContext(testContext, true)). New() verifier, _ := material.pgp.Verify(). VerificationKeys(material.keyRingTestPublic). VerificationContext(NewVerificationContext(testContext, true, 0)). New() testSignVerifyDetachedStream(t, signer, verifier, Bytes, len(material.keyRingTestPrivate.entities)) }) } } func TestSignVerifyStreamDetachedArmor(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { signer, _ := material.pgp.Sign(). SigningKeys(material.keyRingTestPrivate). Detached(). New() verifier, _ := material.pgp.Verify(). VerificationKeys(material.keyRingTestPublic). New() testSignVerifyDetachedStream(t, signer, verifier, Armor, len(material.keyRingTestPrivate.entities)) }) } } func TestSignVerifyCleartext(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { signer, _ := material.pgp.Sign(). SigningKeys(material.keyRingTestPrivate). New() verifier, _ := material.pgp.Verify(). VerificationKeys(material.keyRingTestPublic). New() testSignVerifyCleartext(t, signer, verifier) }) } } func TestSignArmor(t *testing.T) { for _, material := range testMaterialForProfiles { t.Run(material.profileName, func(t *testing.T) { isV6 := material.keyRingTestPrivate.GetKeys()[0].isV6() signer, _ := material.pgp.Sign(). SigningKeys(material.keyRingTestPrivate). New() armoredSignature, err := signer.Sign([]byte(testMessageString), Armor) if err != nil { t.Fatal("Expected no error in singing, got:", err) } hasChecksum := containsChecksum(string(armoredSignature)) if isV6 && hasChecksum { t.Fatalf("V6 messages should not have a checksum") } }) } } func testSignVerify( t *testing.T, signer PGPSign, verifier PGPVerify, detached bool, encoding int8, //nolint:unparam numberOfSigsToVerify int, ) { messageBytes := []byte(messageToSign) signature, err := signer.Sign(messageBytes, encoding) if err != nil { t.Fatal("Expected no error while signing the message, got:", err) } var verifyResult *VerifyResult if detached { verifyResult, err = verifier.VerifyDetached(messageBytes, signature, encoding) } else { verifyDataResult, err := verifier.VerifyInline(signature, encoding) if err != nil { t.Fatal("Expected no error while verifying the message, got:", err) } if !bytes.Equal(messageBytes, verifyDataResult.Bytes()) { t.Fatal("Expected read message in verification to be equal to the input message") } verifyResult = &verifyDataResult.VerifyResult } if err != nil { t.Fatal("Expected no error while verifying the message, got:", err) } if err = verifyResult.SignatureError(); err != nil { t.Fatal("Expected no error while verifying the detached signature, got:", err) } if len(verifyResult.Signatures) != numberOfSigsToVerify { t.Fatalf("Not enough signatures verified, should be %d", numberOfSigsToVerify) } for _, verifiedSignature := range verifyResult.Signatures { if verifiedSignature.SignatureError != nil { t.Fatal("One of the contained signatures did not correctly verify ", verifiedSignature.SignatureError.Message) } } } func testSignVerifyStream( t *testing.T, signer PGPSign, verifier PGPVerify, encoding int8, numberOfSigsToVerify int, ) { messageBytes := []byte(messageToSign) var messageBuffer bytes.Buffer signingWriter, err := signer.SigningWriter(&messageBuffer, encoding) if err != nil { t.Fatal("Expected no error while signing the message, got:", err) } _, err = signingWriter.Write(messageBytes) if err != nil { t.Fatal("Expected no error while writing message, got:", err) } err = signingWriter.Close() if err != nil { t.Fatal("Expected no error while sining message, got:", err) } verifyingReader, err := verifier.VerifyingReader(nil, &messageBuffer, encoding) if err != nil { t.Fatal("Expected no error while verifying the message, got:", err) } messageOut, err := verifyingReader.ReadAll() if err != nil { t.Fatal("Expected no error while verifying the message, got:", err) } verifyResult, err := verifyingReader.VerifySignature() if err != nil { t.Fatal("Expected no error while verifying the message, got:", err) } if err = verifyResult.SignatureError(); err != nil { t.Fatal("Expected no error while verifying the detached signature, got:", err) } if !bytes.Equal(messageOut, messageBytes) { t.Fatal("Expected read message in verification to be equal to the input message") } if len(verifyResult.Signatures) != numberOfSigsToVerify { t.Fatalf("Not enough signatures verified, should be %d", numberOfSigsToVerify) } for _, verifiedSignature := range verifyResult.Signatures { if verifiedSignature.SignatureError != nil { t.Fatal("One of the contained signatures did not correctly verify ", verifiedSignature.SignatureError.Message) } } } func testSignVerifyDetachedStream( t *testing.T, signer PGPSign, verifier PGPVerify, encoding int8, numberOfSigsToVerify int, ) { messageBytes := []byte(messageCleartext) var signatureBuffer bytes.Buffer signingWriter, err := signer.SigningWriter(&signatureBuffer, encoding) if err != nil { t.Fatal("Expected no error while signing the message, got:", err) } _, err = signingWriter.Write(messageBytes) if err != nil { t.Fatal("Expected no error while writing message, got:", err) } err = signingWriter.Close() if err != nil { t.Fatal("Expected no error while sining message, got:", err) } verifyingReader, _ := verifier.VerifyingReader(bytes.NewReader(messageBytes), &signatureBuffer, encoding) verifyResult, err := verifyingReader.DiscardAllAndVerifySignature() if err != nil { t.Fatal("Expected no error while verifying the message, got:", err) } if err = verifyResult.SignatureError(); err != nil { t.Fatal("Expected no error while verifying the detached signature, got:", err) } if len(verifyResult.Signatures) != numberOfSigsToVerify { t.Fatalf("Not enough signatures verified, should be %d", numberOfSigsToVerify) } for _, verifiedSignature := range verifyResult.Signatures { if verifiedSignature.SignatureError != nil { t.Fatal("One of the contained signatures did not correctly verify ", verifiedSignature.SignatureError.Message) } } } func testSignVerifyCleartext(t *testing.T, signer PGPSign, verifier PGPVerify) { messageBytes := []byte(messageCleartext) cleartextMessage, err := signer.SignCleartext(messageBytes) if err != nil { t.Fatal("Expected no error while signing the message, got:", err) } result, err := verifier.VerifyCleartext(cleartextMessage) if err != nil { t.Fatal("Expected no error while verifying the message, got:", err) } if err = result.SignatureError(); err != nil { t.Fatal("Expected no signature error while verifying the detached signature, got:", err) } assert.Exactly(t, expectedMessageCleartext, string(result.Cleartext())) } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/signature.go000066400000000000000000000303331472137411600244470ustar00rootroot00000000000000package crypto import ( "bytes" "fmt" "time" pgpErrors "github.com/ProtonMail/go-crypto/openpgp/errors" "github.com/ProtonMail/go-crypto/openpgp/packet" openpgp "github.com/ProtonMail/go-crypto/openpgp/v2" "github.com/pkg/errors" "github.com/ProtonMail/gopenpgp/v3/constants" ) // VerifiedSignature is a result of a signature verification. type VerifiedSignature struct { Signature *packet.Signature SignedBy *Key SignatureError *SignatureVerificationError } // SignatureVerificationError is returned from Decrypt and VerifyDetached // functions when signature verification fails. type SignatureVerificationError struct { Status int Message string Cause error } // VerifyResult is a result of a pgp message signature verification. type VerifyResult struct { // All signatures found in the message. Signatures []*VerifiedSignature // The selected signature for the result. // i.e., the first successfully verified signature in Signatures // or the last signature Signatures[len(Signatures)-1]. selectedSignature *VerifiedSignature // The signature error of the selected signature. // Is nil for a successful verification. signatureError *SignatureVerificationError } // SignatureCreationTime returns the creation time of // the selected verified signature if found, else returns 0. func (vr *VerifyResult) SignatureCreationTime() int64 { if vr.selectedSignature == nil || vr.selectedSignature.Signature == nil { return 0 } return vr.selectedSignature.Signature.CreationTime.Unix() } // SignedWithType returns the type of the signature if found, else returns 0. // Not supported in go-mobile use SignedWithTypeInteger instead. func (vr *VerifyResult) SignedWithType() packet.SignatureType { if vr.selectedSignature == nil || vr.selectedSignature.Signature == nil { return 0 } return vr.selectedSignature.Signature.SigType } // SignedWithTypeInt8 returns the type of the signature as int8 type if found, else returns 0. // See constants.SigType... for the different types. func (vr *VerifyResult) SignedWithTypeInt8() int8 { return int8(vr.SignedWithType()) } // SignedByKeyId returns the key id of the key that was used to verify the selected signature, // if found, else returns 0. // Not supported in go-mobile use SignedByKeyIdString instead. func (vr *VerifyResult) SignedByKeyId() uint64 { if vr.selectedSignature == nil || vr.selectedSignature.Signature == nil { return 0 } return *vr.selectedSignature.Signature.IssuerKeyId } // SignedByKeyIdHex returns the key id of the key that was used to verify the selected signature // as a hex encoded string. // Helper for go-mobile. func (vr *VerifyResult) SignedByKeyIdHex() string { return keyIDToHex(vr.SignedByKeyId()) } // SignedByFingerprint returns the key fingerprint of the key that was used to verify the selected signature, // if found, else returns nil. func (vr *VerifyResult) SignedByFingerprint() []byte { if vr.selectedSignature == nil || vr.selectedSignature.Signature == nil { return nil } if vr.selectedSignature.Signature.IssuerFingerprint != nil { return vr.selectedSignature.Signature.IssuerFingerprint } if vr.selectedSignature.SignedBy != nil { return vr.selectedSignature.SignedBy.GetFingerprintBytes() } return nil } // SignedByKey returns the key that was used to verify the selected signature, // if found, else returns nil. func (vr *VerifyResult) SignedByKey() *Key { if vr.selectedSignature == nil || vr.selectedSignature.Signature == nil { return nil } key := vr.selectedSignature.SignedBy if key == nil { return nil } return &Key{ entity: key.entity, } } // Signature returns the serialized openpgp signature packet of the selected signature. func (vr *VerifyResult) Signature() ([]byte, error) { if vr.selectedSignature == nil || vr.selectedSignature.Signature == nil { return nil, errors.New("gopenpgp: no signature present") } var serializedSignature bytes.Buffer if err := vr.selectedSignature.Signature.Serialize(&serializedSignature); err != nil { return nil, errors.Wrap(err, "gopenpgp: signature serialization failed") } return serializedSignature.Bytes(), nil } // SignatureError returns nil if no signature err occurred else // the signature error. func (vr *VerifyResult) SignatureError() error { if vr == nil || vr.signatureError == nil { return nil } return *vr.signatureError } // SignatureErrorExplicit returns nil if no signature err occurred else // the explicit signature error. func (vr *VerifyResult) SignatureErrorExplicit() *SignatureVerificationError { return vr.signatureError } // ConstrainToTimeRange updates the signature result to only consider // signatures with a creation time within the given time frame. // unixFrom and unixTo are in unix time and are inclusive. func (vr *VerifyResult) ConstrainToTimeRange(unixFrom int64, unixTo int64) { for _, signature := range vr.Signatures { if signature.Signature != nil && signature.SignatureError == nil { sigUnixTime := signature.Signature.CreationTime.Unix() if sigUnixTime < unixFrom || sigUnixTime > unixTo { sigError := newSignatureFailed(errors.New("gopenpgp: signature creation time is out of range")) signature.SignatureError = &sigError } } } // Reselect vr.selectSignature() } // Error is the base method for all errors. func (e SignatureVerificationError) Error() string { if e.Cause != nil { return fmt.Sprintf("Signature Verification Error: %v caused by %v", e.Message, e.Cause) } return fmt.Sprintf("Signature Verification Error: %v", e.Message) } // Unwrap returns the cause of failure. func (e SignatureVerificationError) Unwrap() error { return e.Cause } // ------------------ // Internal functions // ------------------ // selectSignature selects the main signature to show in the result. // Selection policy: // first successfully verified or // last signature with an error and a matching key or // last signature with an error if no key matched. func (vr *VerifyResult) selectSignature() { var keyMatch bool for _, signature := range vr.Signatures { if signature.SignedBy != nil { keyMatch = true vr.selectedSignature = signature vr.signatureError = signature.SignatureError if signature.SignatureError == nil { break } } } if !keyMatch && len(vr.Signatures) > 0 { signature := vr.Signatures[len(vr.Signatures)-1] vr.selectedSignature = signature vr.signatureError = signature.SignatureError } } // newSignatureFailed creates a new SignatureVerificationError, type // SignatureFailed. func newSignatureBadContext(cause error) SignatureVerificationError { return SignatureVerificationError{ Status: constants.SIGNATURE_BAD_CONTEXT, Message: "Invalid signature context", Cause: cause, } } func newSignatureFailed(cause error) SignatureVerificationError { return SignatureVerificationError{ Status: constants.SIGNATURE_FAILED, Message: "Invalid signature", Cause: cause, } } // newSignatureNotSigned creates a new SignatureVerificationError, type // SignatureNotSigned. func newSignatureNotSigned() SignatureVerificationError { return SignatureVerificationError{ Status: constants.SIGNATURE_NOT_SIGNED, Message: "Missing signature", } } // newSignatureNoVerifier creates a new SignatureVerificationError, type // SignatureNoVerifier. func newSignatureNoVerifier() SignatureVerificationError { return SignatureVerificationError{ Status: constants.SIGNATURE_NO_VERIFIER, Message: "No matching signature", } } // processSignatureExpiration handles signature time verification manually, so // we can ignore signature expired errors if configured so. func processSignatureExpiration(sig *packet.Signature, toCheck error, verifyTime int64, disableTimeCheck bool) error { if sig == nil || !errors.Is(toCheck, pgpErrors.ErrSignatureExpired) { return toCheck } if disableTimeCheck || verifyTime == 0 { return nil } return toCheck } func createVerifyResult( md *openpgp.MessageDetails, verifierKey *KeyRing, verificationContext *VerificationContext, verifyTime int64, disableTimeCheck bool, ) (*VerifyResult, error) { if !md.IsSigned { signatureError := newSignatureNotSigned() return &VerifyResult{ signatureError: &signatureError, }, nil } if !md.IsVerified { return nil, errors.New("gopenpgp: message has not been verified") } verifiedSignatures := make([]*VerifiedSignature, len(md.SignatureCandidates)) for candidateIndex, signature := range md.SignatureCandidates { var singedBy *Key if signature.SignedBy != nil { singedBy = &Key{ entity: signature.SignedBy.Entity, } } verifiedSignature := &VerifiedSignature{ Signature: signature.CorrespondingSig, SignedBy: singedBy, } signature.SignatureError = processSignatureExpiration( signature.CorrespondingSig, signature.SignatureError, verifyTime, disableTimeCheck, ) var signatureError SignatureVerificationError switch { case verifierKey == nil || len(verifierKey.entities) == 0 || errors.Is(signature.SignatureError, pgpErrors.ErrUnknownIssuer): signatureError = newSignatureNoVerifier() case signature.SignatureError != nil: signatureError = newSignatureFailed(signature.SignatureError) case verificationContext != nil: err := verificationContext.verifyContext(signature.CorrespondingSig) if err != nil { signatureError = newSignatureBadContext(err) } } if signatureError.Status != constants.SIGNATURE_OK { verifiedSignature.SignatureError = &signatureError } verifiedSignatures[candidateIndex] = verifiedSignature } verifyResult := &VerifyResult{ Signatures: verifiedSignatures, } // Select the signature to show in the result verifyResult.selectSignature() return verifyResult, nil } // SigningContext gives the context that will be // included in the signature's notation data. type SigningContext struct { Value string IsCritical bool } // NewSigningContext creates a new signing context. // The value is set to the notation data. // isCritical controls whether the notation is flagged as a critical packet. func NewSigningContext(value string, isCritical bool) *SigningContext { return &SigningContext{Value: value, IsCritical: isCritical} } func (context *SigningContext) getNotation() *packet.Notation { return &packet.Notation{ Name: constants.SignatureContextName, Value: []byte(context.Value), IsCritical: context.IsCritical, IsHumanReadable: true, } } // VerificationContext gives the context that will be // used to verify the signature. type VerificationContext struct { Value string IsRequired bool RequiredAfter int64 } // NewVerificationContext creates a new verification context. // The value is checked against the signature's notation data. // If isRequired is false, the signature is allowed to have no context set. // If requiredAfter is != 0, the signature is allowed to have no context set if it // was created before the unix time set in requiredAfter. func NewVerificationContext(value string, isRequired bool, requiredAfter int64) *VerificationContext { return &VerificationContext{ Value: value, IsRequired: isRequired, RequiredAfter: requiredAfter, } } func (context *VerificationContext) isRequiredAtTime(signatureTime time.Time) bool { return context.IsRequired && (context.RequiredAfter == 0 || signatureTime.After(time.Unix(context.RequiredAfter, 0))) } func findContext(notations []*packet.Notation) (string, error) { context := "" for _, notation := range notations { if notation.Name == constants.SignatureContextName { if context != "" { return "", errors.New("gopenpgp: signature has multiple context notations") } if !notation.IsHumanReadable { return "", errors.New("gopenpgp: context notation was not set as human-readable") } context = string(notation.Value) } } return context, nil } func (context *VerificationContext) verifyContext(sig *packet.Signature) error { if sig == nil { return errors.New("gopenpgp: no signature packet found for signature") } signatureContext, err := findContext(sig.Notations) if err != nil { return err } if signatureContext != context.Value { contextRequired := context.isRequiredAtTime(sig.CreationTime) if contextRequired { return errors.New("gopenpgp: signature did not have the required context") } else if signatureContext != "" { return errors.New("gopenpgp: signature had a wrong context") } } return nil } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/signature_test.go000066400000000000000000000412471472137411600255140ustar00rootroot00000000000000package crypto import ( "bytes" "encoding/hex" "io" "os" "regexp" "testing" "github.com/ProtonMail/go-crypto/openpgp/packet" "github.com/ProtonMail/gopenpgp/v3/armor" "github.com/ProtonMail/gopenpgp/v3/constants" "github.com/ProtonMail/gopenpgp/v3/internal" "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) const signedPlainText = "Signed message\n" var textSignature, binSignature []byte var signatureTest = regexp.MustCompile("(?s)^-----BEGIN PGP SIGNATURE-----.*-----END PGP SIGNATURE-----$") func getSignatureType(sig []byte) (packet.SignatureType, error) { sigPacket, err := getSignaturePacket(sig) if err != nil { return 0, err } return sigPacket.SigType, nil } func testSignerText() PGPSign { signer, _ := testPGP.Sign(). SigningKeys(keyRingTestPrivate). Utf8(). Detached(). New() return signer } func testSigner() PGPSign { signer, _ := testPGP.Sign(). SigningKeys(keyRingTestPrivate). Detached(). New() return signer } func testVerifier() PGPVerify { verifier, _ := testPGP.Verify(). VerificationKeys(keyRingTestPublic). VerifyTime(testTime). New() return verifier } func TestSignTextDetached(t *testing.T) { var err error textSignature, err = testSignerText().Sign([]byte(signedPlainText), Bytes) if err != nil { t.Fatal("Cannot generate signature:", err) } armoredSignature, err := armor.ArmorPGPSignatureBinary(textSignature) if err != nil { t.Fatal("Cannot armor signature:", err) } sigType, err := getSignatureType(textSignature) if err != nil { t.Fatal("Cannot get signature type:", err) } if sigType != packet.SigTypeText { t.Fatal("Signature type was not text") } assert.Regexp(t, signatureTest, string(armoredSignature)) verificationError, err := testVerifier().VerifyDetached([]byte(signedPlainText), textSignature, Bytes) if err != nil { t.Fatal(err) } if err = verificationError.SignatureError(); err != nil { t.Fatal("Cannot verify plaintext signature:", err) } fakeMessage := []byte("wrong text") verificationError, err = testVerifier().VerifyDetached(fakeMessage, textSignature, Bytes) if err != nil { t.Fatal(err) } checkVerificationError(t, verificationError.SignatureError(), constants.SIGNATURE_FAILED) } func TestSignNonUtf8Text(t *testing.T) { var err error var nonUft8, _ = hex.DecodeString("fc80808080af") textSignature, err = testSignerText().Sign(nonUft8, Bytes) if !errors.Is(err, internal.ErrIncorrectUtf8) { t.Fatal("Expected not valid utf8 error") } } func checkVerificationError(t *testing.T, err error, expectedStatus int) { if err == nil { t.Fatalf("Expected a verification error") } castedErr := &SignatureVerificationError{} isType := errors.As(err, castedErr) if !isType { t.Fatalf("Error was not a verification error: %v", err) } if castedErr.Status != expectedStatus { t.Fatalf("Expected status to be %d got %d", expectedStatus, castedErr.Status) } } func TestSignBinDetached(t *testing.T) { var err error binSignature, err = testSigner().Sign([]byte(signedPlainText), Bytes) if err != nil { t.Fatal("Cannot generate signature:", err) } armoredSignature, err := armor.ArmorPGPSignatureBinary(binSignature) if err != nil { t.Fatal("Cannot armor signature:", err) } sigType, err := getSignatureType(binSignature) if err != nil { t.Fatal("Cannot get signature type:", err) } if sigType != packet.SigTypeBinary { t.Fatal("Signature type was not binary") } assert.Regexp(t, signatureTest, string(armoredSignature)) verificationError, err := testVerifier().VerifyDetached([]byte(signedPlainText), binSignature, Bytes) if err != nil { t.Fatal(err) } if err = verificationError.SignatureError(); err != nil { t.Fatal("Cannot verify binary signature:", err) } } func Test_KeyRing_GetVerifiedSignatureTimestampSuccess(t *testing.T) { message := []byte(testMessage) var timeLocal int64 = 1600000000 signer, _ := testPGP.Sign(). SigningKeys(keyRingTestPrivate). SignTime(timeLocal). Detached(). New() signature, err := signer.Sign(message, Bytes) if err != nil { t.Errorf("Got an error while generating the signature: %v", err) } verifier, _ := testPGP.Verify(). VerificationKeys(keyRingTestPublic). VerifyTime(timeLocal). New() verificationResult, err := verifier.VerifyDetached(message, signature, Bytes) if err != nil { t.Fatal(err) } actualTime := verificationResult.SignatureCreationTime() if err != nil { t.Errorf("Got an error while parsing the signature creation time: %v", err) } if timeLocal != actualTime { t.Errorf("Expected creation time to be %d, got %d", timeLocal, actualTime) } } func Test_KeyRing_GetVerifiedSignatureWithTwoKeysTimestampSuccess(t *testing.T) { publicKey1Armored, err := os.ReadFile("testdata/signature/publicKey1") if err != nil { t.Errorf("Couldn't read the public key file: %v", err) } publicKey1 := parseKey(t, string(publicKey1Armored)) publicKey2Armored, err := os.ReadFile("testdata/signature/publicKey2") if err != nil { t.Errorf("Couldn't read the public key file: %v", err) } publicKey2 := parseKey(t, string(publicKey2Armored)) message := []byte("hello world") signatureArmored, err := os.ReadFile("testdata/signature/detachedSigSignedTwice") if err != nil { t.Errorf("Couldn't read the signature file: %v", err) } signature, err := armor.UnarmorBytes(signatureArmored) if err != nil { t.Errorf("Got an error while parsing the signature: %v", err) } time1 := getTimestampOfIssuer(signature, publicKey1.GetKeyID()) time2 := getTimestampOfIssuer(signature, publicKey2.GetKeyID()) keyRing, err := NewKeyRing(publicKey1) if err != nil { t.Errorf("Got an error while building the key ring: %v", err) } err = keyRing.AddKey(publicKey2) if err != nil { t.Errorf("Got an error while adding key 2 to the key ring: %v", err) } verifier, _ := testPGP.Verify(). VerificationKeys(keyRing). DisableVerifyTimeCheck(). New() verificationResult, err := verifier.VerifyDetached(message, signature, Bytes) if err != nil { t.Fatal(err) } actualTime := verificationResult.SignatureCreationTime() otherTime := verificationResult.Signatures[1].Signature.CreationTime.Unix() if err != nil { t.Errorf("Got an error while parsing the signature creation time: %v", err) } if time2 != otherTime { t.Errorf("Expected creation time to be %d, got %d", otherTime, time2) } if time1 != actualTime { t.Errorf("Expected creation time to be %d, got %d", actualTime, time1) } } func parseKey(t *testing.T, keyArmored string) *Key { key, err := NewKeyFromArmored(keyArmored) if err != nil { t.Errorf("Couldn't parse key: %v", err) return nil } return key } func getTimestampOfIssuer(signature []byte, keyID uint64) int64 { packets := packet.NewReader(bytes.NewReader(signature)) var err error var p packet.Packet for { p, err = packets.Next() if errors.Is(err, io.EOF) { break } if err != nil { continue } sigPacket, ok := p.(*packet.Signature) if !ok { continue } var outBuf bytes.Buffer err = sigPacket.Serialize(&outBuf) if err != nil { continue } if *sigPacket.IssuerKeyId == keyID { return sigPacket.CreationTime.Unix() } } return -1 } func Test_KeyRing_GetVerifiedSignatureTimestampError(t *testing.T) { message := []byte(testMessage) var timeLocal int64 = 1600000000 signer, _ := testPGP.Sign(). SignTime(timeLocal). SigningKeys(keyRingTestPrivate). Detached(). New() signature, err := signer.Sign(message, Bytes) if err != nil { t.Errorf("Got an error while generating the signature: %v", err) } messageCorrupted := []byte("Ciao world!") verifier, _ := testPGP.Verify(). VerificationKeys(keyRingTestPublic). VerifyTime(timeLocal). New() verificationResult, err := verifier.VerifyDetached(messageCorrupted, signature, Bytes) if err != nil { t.Fatal(err) } if verificationResult.SignatureError() == nil { t.Errorf("Expected an error while parsing the creation time of a wrong signature, got nil") } } func Test_SignDetachedWithNonCriticalContext(t *testing.T) { // given context := NewSigningContext( "test-context", false, ) signer, _ := testPGP.Sign(). SigningKeys(keyRingTestPrivate). SigningContext(context). Detached(). New() // when signature, err := signer.Sign([]byte(testMessage), Bytes) // then if err != nil { t.Fatal(err) } p, err := packet.Read(bytes.NewReader(signature)) if err != nil { t.Fatal(err) } sig, ok := p.(*packet.Signature) if !ok { t.Fatal("Packet was not a signature") } notations := sig.Notations if len(notations) != 2 { t.Fatal("Wrong number of notations") } notation := notations[0] if notation.Name != constants.SignatureContextName { t.Fatalf("Expected notation name to be %s, got %s", constants.SignatureContextName, notation.Name) } if string(notation.Value) != context.Value { t.Fatalf("Expected notation value to be %s, got %s", context.Value, notation.Value) } if notation.IsCritical { t.Fatal("Expected notation to be non critical") } if !notation.IsHumanReadable { t.Fatal("Expected notation to be human readable") } } func Test_SignDetachedWithCriticalContext(t *testing.T) { // given context := NewSigningContext( "test-context", true, ) signer, _ := testPGP.Sign(). SigningKeys(keyRingTestPrivate). SigningContext(context). Detached(). New() // when signature, err := signer.Sign([]byte(testMessage), Bytes) // then if err != nil { t.Fatal(err) } p, err := packet.Read(bytes.NewReader(signature)) if err != nil { t.Fatal(err) } sig, ok := p.(*packet.Signature) if !ok { t.Fatal("Packet was not a signature") } notations := sig.Notations if len(notations) != 2 { t.Fatal("Wrong number of notations") } notation := notations[0] if notation.Name != constants.SignatureContextName { t.Fatalf("Expected notation name to be %s, got %s", constants.SignatureContextName, notation.Name) } if string(notation.Value) != context.Value { t.Fatalf("Expected notation value to be %s, got %s", context.Value, notation.Value) } if !notation.IsCritical { t.Fatal("Expected notation to be critical") } if !notation.IsHumanReadable { t.Fatal("Expected notation to be human readable") } } func Test_VerifyWithUnknownCriticalContext(t *testing.T) { // given signatureArmored, err := os.ReadFile("testdata/signature/critical_context_detached_sig") if err != nil { t.Fatal(err) } sig, err := armor.UnarmorBytes(signatureArmored) if err != nil { t.Fatal(err) } // when verifier, _ := testPGP.Verify(). VerificationKeys(keyRingTestPublic). DisableVerifyTimeCheck(). New() result, err := verifier.VerifyDetached([]byte(testMessage), sig, Bytes) if err != nil { t.Fatal(err) } // then checkVerificationError(t, result.SignatureError(), constants.SIGNATURE_FAILED) } func Test_VerifyWithUnKnownNonCriticalContext(t *testing.T) { // given signatureArmored, err := os.ReadFile("testdata/signature/non_critical_context_detached_sig") if err != nil { t.Fatal(err) } sig, err := armor.UnarmorBytes(signatureArmored) if err != nil { t.Fatal(err) } // when verifier, _ := testPGP.Verify(). VerificationKeys(keyRingTestPublic). DisableVerifyTimeCheck(). New() result, err := verifier.VerifyDetached([]byte(testMessage), sig, Bytes) if err != nil { t.Fatal(err) } // then if err = result.SignatureError(); err != nil { t.Fatalf("Expected no verification error, got %v", err) } } func Test_VerifyWithKnownCriticalContext(t *testing.T) { // given signatureArmored, err := os.ReadFile("testdata/signature/critical_context_detached_sig") if err != nil { t.Fatal(err) } sig, err := armor.UnarmorBytes(signatureArmored) if err != nil { t.Fatal(err) } verificationContext := NewVerificationContext( "test-context", false, 0, ) // when verifier, _ := testPGP.Verify(). VerificationKeys(keyRingTestPublic). VerificationContext(verificationContext). DisableVerifyTimeCheck(). New() result, err := verifier.VerifyDetached([]byte(testMessage), sig, Bytes) if err != nil { t.Fatal(err) } // then if err = result.SignatureError(); err != nil { t.Fatalf("Expected no verification error, got %v", err) } } func Test_VerifyWithWrongContext(t *testing.T) { // given signatureArmored, err := os.ReadFile("testdata/signature/critical_context_detached_sig") if err != nil { t.Fatal(err) } sig, err := armor.UnarmorBytes(signatureArmored) if err != nil { t.Fatal(err) } verificationContext := NewVerificationContext( "another-test-context", false, 0, ) // when verifier, _ := testPGP.Verify(). VerificationKeys(keyRingTestPublic). VerificationContext(verificationContext). DisableVerifyTimeCheck(). New() result, err := verifier.VerifyDetached([]byte(testMessage), sig, Bytes) if err != nil { t.Fatal(err) } // then checkVerificationError(t, result.SignatureError(), constants.SIGNATURE_BAD_CONTEXT) } func Test_VerifyWithMissingNonRequiredContext(t *testing.T) { // given signatureArmored, err := os.ReadFile("testdata/signature/no_context_detached_sig") if err != nil { t.Fatal(err) } sig, err := armor.UnarmorBytes(signatureArmored) if err != nil { t.Fatal(err) } verificationContext := NewVerificationContext( "test-context", false, 0, ) // when verifier, _ := testPGP.Verify(). VerificationKeys(keyRingTestPublic). VerificationContext(verificationContext). DisableVerifyTimeCheck(). New() result, err := verifier.VerifyDetached([]byte(testMessage), sig, Bytes) if err != nil { t.Fatal(err) } // then if err = result.SignatureError(); err != nil { t.Fatalf("Expected no verification error, got %v", err) } } func Test_VerifyWithMissingRequiredContext(t *testing.T) { // given signatureArmored, err := os.ReadFile("testdata/signature/no_context_detached_sig") if err != nil { t.Fatal(err) } sig, err := armor.UnarmorBytes(signatureArmored) if err != nil { t.Fatal(err) } verificationContext := NewVerificationContext( "test-context", true, 0, ) // when verifier, _ := testPGP.Verify(). VerificationKeys(keyRingTestPublic). VerificationContext(verificationContext). DisableVerifyTimeCheck(). New() result, err := verifier.VerifyDetached([]byte(testMessage), sig, Bytes) if err != nil { t.Fatal(err) } // then checkVerificationError(t, result.SignatureError(), constants.SIGNATURE_BAD_CONTEXT) } func Test_VerifyWithMissingRequiredContextBeforeCutoff(t *testing.T) { // given signatureArmored, err := os.ReadFile("testdata/signature/no_context_detached_sig") if err != nil { t.Fatal(err) } sig, err := armor.UnarmorBytes(signatureArmored) if err != nil { t.Fatal(err) } p, err := packet.Read(bytes.NewReader(sig)) if err != nil { t.Fatal(err) } sigPacket, ok := p.(*packet.Signature) if !ok { t.Fatal("Packet was not a signature") } verificationContext := NewVerificationContext( "test-context", true, sigPacket.CreationTime.Unix()+10000, ) // when verifier, _ := testPGP.Verify(). VerificationKeys(keyRingTestPublic). VerificationContext(verificationContext). DisableVerifyTimeCheck(). New() result, err := verifier.VerifyDetached([]byte(testMessage), sig, Bytes) if err != nil { t.Fatal(err) } // then if err = result.SignatureError(); err != nil { t.Fatalf("Expected no verification error, got %v", err) } } func Test_VerifyWithMissingRequiredContextAfterCutoff(t *testing.T) { // given signatureArmored, err := os.ReadFile("testdata/signature/no_context_detached_sig") if err != nil { t.Fatal(err) } sig, err := armor.UnarmorBytes(signatureArmored) if err != nil { t.Fatal(err) } p, err := packet.Read(bytes.NewReader(sig)) if err != nil { t.Fatal(err) } sigPacket, ok := p.(*packet.Signature) if !ok { t.Fatal("Packet was not a signature") } verificationContext := NewVerificationContext( "test-context", true, sigPacket.CreationTime.Unix()-10000, ) // when verifier, _ := testPGP.Verify(). VerificationKeys(keyRingTestPublic). VerificationContext(verificationContext). DisableVerifyTimeCheck(). New() result, err := verifier.VerifyDetached([]byte(testMessage), sig, Bytes) if err != nil { t.Fatal(err) } // then checkVerificationError(t, result.SignatureError(), constants.SIGNATURE_BAD_CONTEXT) } func Test_VerifyWithDoubleContext(t *testing.T) { // given signatureArmored, err := os.ReadFile("testdata/signature/double_critical_context_detached_sig") if err != nil { t.Fatal(err) } sig, err := armor.UnarmorBytes(signatureArmored) if err != nil { t.Fatal(err) } verificationContext := NewVerificationContext( "test-context", true, 0, ) // when verifier, _ := testPGP.Verify(). VerificationKeys(keyRingTestPublic). VerificationContext(verificationContext). DisableVerifyTimeCheck(). New() result, err := verifier.VerifyDetached([]byte(testMessage), sig, Bytes) if err != nil { t.Fatal(err) } // then checkVerificationError(t, result.SignatureError(), constants.SIGNATURE_BAD_CONTEXT) } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/000077500000000000000000000000001472137411600237265ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/att_body000066400000000000000000000261601472137411600254630ustar00rootroot000000000000000v8AACFOAU9M0+V/b5/xKiNmDeikpJg1Z/yYyaZfew++SiPoi0Q+7Bt/dyxcCeCZW7UcZB04JvxOTthoE52lmkFHT4WGIIP1YxmWWlbLKkcBF2Gnp6xx1mdm1INSpYt8gG28UgGYwMbn5cFNJq0zhbQBVSVc604/JUxVRlcuqgKDd3NFY8Omgxg5DO6aMfqJw2mlmttVE/j/m/oG61ZWG9ujD17WepeZVZG19CYNOVGnHyzngPGtyxRwZXU6YczCAPzOVkD7Ak5Yy/LmQVhC+RjBSFONBJGTsIicURzaohUIb23tu1qEcXFyTfhV92+NTwBpCPl94Incn+Beey1VRpr6DFWLbcS2xDBpDabUumt62b4dLR5mGjxU4c3eF9Re4llKNQn/dO1hOy3Tqy4AQUt3MVnB3ABqlZsambl+lNKGcqEaRz2OrehuB6NETr3KOVWfrth9e8DATTwnSjSbtiez1NMfdNXis0g3PhU34DhxzePFy0pmxA3HOTrip6NE352WjfwKOh/n+m7TcrJ7tyfUTqy9ms6/ejs7vkpNIM1FtIJ4+0i+mPl7qPXG7dhqNBFidfzqU1HL0txSDY3yzks5RkOM3kjClJT0eFaHUtFGCZFILp3muoZh2XEAhQZ7FDThG5xaegwNzSM3gVTBX9mB7yDskRJjI/j1kHhiMg+ijtmMrYsd9bUj73RTBTlvCnT7kffSNy08RpC0h984O1AsEe7VoJbCMq7fBKatt6Dze3xFLsgxzAPKykFyzFGdTEIU37h9geYf+OhyTk3NXxhapsdZLYWz9cOF/kcn94b0aBTvPFLcI91yOeidxfLqoSdH3uSXfJUCMkopgDLyqrRcnjPNOo7gP6LxJ5YM8IwRj6ULOZjdnWzwyiAjWobqy2UBjeDfdxcUIGmiS1nvxoEQdiLb7x1VyvMCOE/qGR4bK8jy42z6kW0GUYHC/+W7M+C75N+SE9aCibmOOpJ4kTkzQiG+qLr13FGyZI7SLr+/5nVYKmtN9+q1RAuuPUTzXw5o6nfHgVRPqycgpIvSlAMj7frNoELvlCcC8hhuiIiiaRxYBknQSCq6N7iYhroQpNqSia3Rp6jF/+4sOdF+GYj6R3/8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-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/att_cleartext000066400000000000000000000124071472137411600265200ustar00rootroot00000000000000Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus eget imperdiet justo. Phasellus a tellus a lorem tempus rhoncus quis iaculis ante. Nullam et arcu cursus, vulputate quam sagittis, rutrum arcu. Nam egestas mauris a volutpat commodo. Vivamus eu ullamcorper turpis. Etiam eget odio tempor eros tempor bibendum id at mi. Vestibulum ipsum ipsum, auctor eget eros ut, feugiat sollicitudin libero. Aenean id ipsum urna. Donec sed est interdum, eleifend dolor et, viverra dui. Fusce felis enim, interdum a rhoncus eget, pellentesque sit amet erat. Mauris consequat mauris enim, sit amet blandit massa elementum at. Donec quis lorem lectus. Nulla ultricies risus tortor, et auctor magna mattis id. Nullam vel pretium nisl. Aenean hendrerit purus sed interdum porta. Quisque eu porttitor felis. Aliquam tempor mi lorem, vitae placerat elit congue ut. Sed et orci massa. Nunc suscipit auctor diam et dapibus. Nullam vehicula accumsan libero facilisis dignissim. Vestibulum pellentesque cursus tortor, ut porta eros eleifend quis. Vestibulum nec consequat elit. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vestibulum a gravida sapien. In vel vulputate dui. Nam mattis, dui a finibus cursus, lectus enim aliquam ante, ut finibus tortor mauris vel nunc. Nam vehicula nulla nec tortor faucibus mollis. Nunc eget purus non mauris placerat euismod. Mauris ut mi cursus ante efficitur posuere in sit amet orci. Maecenas placerat neque vel congue feugiat. Quisque laoreet viverra posuere. Pellentesque eget mauris dictum, condimentum augue mattis, lacinia est. Duis faucibus ligula orci. Pellentesque hendrerit dolor dolor, nec tempus magna eleifend et. Aliquam eleifend sodales tortor, sit amet rhoncus tellus varius vel. Mauris fermentum faucibus velit. Morbi porta lectus eu consequat elementum. Aenean quis porta sem. Nam vulputate vitae ligula vitae scelerisque. Pellentesque rutrum in tellus nec accumsan. Vestibulum imperdiet dictum ipsum at congue. Phasellus vel metus sagittis, posuere nulla eget, congue urna. Mauris lorem neque, ornare eget efficitur sit amet, aliquam eu neque. Suspendisse sed lectus eleifend, vestibulum orci quis, efficitur ex. Praesent id vulputate dui. Pellentesque sagittis felis sit amet nulla elementum sodales. Phasellus id commodo ante. Curabitur ac ante lorem. Phasellus ante arcu, tristique vitae ipsum quis, placerat pretium augue. Nunc egestas in sem finibus dapibus. Vestibulum luctus hendrerit odio a tempor. In hac habitasse platea dictumst. Phasellus varius facilisis pharetra. Donec eleifend elit blandit, gravida erat vitae, convallis risus. Nulla aliquam convallis velit vel fringilla. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aenean pellentesque, eros a porta rhoncus, lectus tellus aliquet lectus, vitae pharetra metus mauris et risus. Vestibulum facilisis ipsum non augue vehicula convallis. Phasellus eu sodales elit. Proin auctor, est ac vestibulum faucibus, odio arcu viverra ante, sed accumsan massa eros ac quam. Curabitur sit amet quam lectus. Aenean interdum turpis eget neque aliquet, blandit placerat urna accumsan. Nullam vitae consectetur diam, sit amet laoreet leo. Quisque pretium consectetur tellus et pretium. Praesent ut commodo tellus. Fusce finibus dolor vel ex pretium, ut eleifend elit molestie. Donec molestie gravida metus eu luctus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Fusce massa ipsum, sodales ut ullamcorper vel, ultricies et tellus. Nunc pellentesque eu sem quis tincidunt. Nulla justo urna, elementum a libero ut, tempor bibendum nisl. Vestibulum aliquet varius mauris eu pellentesque. Proin elit dui, auctor ac nulla id, tincidunt vulputate turpis. Pellentesque rutrum efficitur dolor, venenatis sollicitudin dolor scelerisque at. Etiam eu velit eu massa dignissim suscipit. In non nibh metus. Nam mi arcu, malesuada iaculis augue nec, imperdiet fermentum lacus. Etiam malesuada risus justo, suscipit volutpat metus sodales eget. Sed sit amet lacus interdum, vehicula tortor eget, convallis turpis. Mauris in aliquam metus, at scelerisque quam. Suspendisse facilisis suscipit mi at mollis. Vestibulum eget purus ut lacus venenatis dictum et id ipsum. Integer in lorem non turpis elementum tempus ut a sem. Curabitur aliquam volutpat fringilla. Nulla sed facilisis sapien, at consequat odio. Pellentesque vehicula tincidunt lacus eget malesuada. Donec porttitor quam nec lacus commodo pellentesque. Cras ut accumsan tellus, ut rhoncus mi. Nullam eget rhoncus ligula. Suspendisse porttitor ac quam sit amet gravida. Cras et porttitor nisi, eget accumsan augue. Proin turpis nibh, hendrerit vitae placerat at, mattis in mi. Sed eu mi nulla. Aenean sit amet condimentum ipsum, nec aliquet felis. Ut a dolor iaculis, commodo tortor ut, viverra ligula. Mauris sed ullamcorper ligula. Ut ornare egestas est, sed pulvinar ipsum lacinia quis. Praesent nec erat vestibulum, interdum ipsum at, pellentesque ipsum. Sed finibus, sapien at hendrerit luctus, metus leo ultrices erat, vitae rutrum augue lacus ut dolor. Mauris elementum nec leo interdum gravida. Cras id enim placerat, fermentum nisi eget, vestibulum sapien. Quisque aliquam, mauris ut tempor facilisis, lacus nisl maximus sapien, eu ultrices ex dolor in risus. Mauris facilisis est scelerisque, interdum erat vel, lobortis nunc. golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/att_key000066400000000000000000000070271472137411600253170ustar00rootroot00000000000000-----BEGIN PGP PRIVATE KEY BLOCK----- Version: ProtonMail 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 VzFZnZqUR/gGwtdUAkPTcIEe8g== =QGmw -----END PGP PRIVATE KEY BLOCK----- golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/att_keypacket000066400000000000000000000005541472137411600265050ustar00rootroot00000000000000wcBMA3NHBIPxZtwdAQf/UTdLZjutQTMFLGhlVazAuBHsIG27zFspkSTTDUtQEzeorOggZX4Kj4xOw0AXOe7n2NhOQzc6td7HkjZf8/+eJP1F+njqvmxy+6wCMBU4wDQ1oQR8YidThIdxdhDjmAtTE24ub0R2N2/ENCAAn1bDg+CACnhFN4AJbtvQA9SzDGjur5AS/G9nieuxE6Br6i2QjLFvGoqvXObmHLApiB22vwcpiGEEzYh3ChO+KLGARCUw2eFtyycF8MqIw9mnN2rTN+jOoHF9lEsxRzHr7Dc47dkPsDlqZYEDZzQ2GG97jZDaMceLW/p5OZk/6ffKJAwgHjgs8p2AOMUglFakezjttA==golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/attachment_keypacket000066400000000000000000000005551472137411600300460ustar00rootroot00000000000000wcBMA0fcZ7XLgmf2AQgAiRsOlnm1kSB4/lr7tYe6pBsRGn10GqwUhrwU5PMKOHdCgnO12jO3y3CzP0Yl/jGhAYja9wLDqH8X0sk3tY32u4Sb1Qe5IuzggAiCa4dwOJj5gEFMTHMzjIMPHR7A70XqUxMhmILye8V4KRm/j4c1sxbzA1rM3lYBumQuB5l/ck0Kgt4ZqxHVXHK5Q1l65FHhSXRj8qnunasHa30TYNzP8nmBA8BinnJxpiQ7FGc2umnUhgkFtjm5ixu9vyjr9ukwDTbwAXXfmY+o7tK7kqIXJcmTL6k2UeC6Mz1AagQtRCRtU+bv/3zGojq/trZo9lom3naIeQYa36Ketmcpj2Qwjg== golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/gpg2.3-aead-pgp-message.pgp000066400000000000000000000003001472137411600305250ustar00rootroot00000000000000^Y7p}@MMRtɑݖ9 #0%;׬j4# RsRAZA"Ĩ?f/L] eѣ^ kE8^ς8&x#2nQ sAСB6ِj~j1%i6s+-I`pgolang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/gpg2.3-aead-test-key.asc000066400000000000000000000016021472137411600300500ustar00rootroot00000000000000-----BEGIN PGP PRIVATE KEY BLOCK----- lIYEYqiY8xYJKwYBBAHaRw8BAQdAlnAqgX8/hgDonAw/IpekRQwfVJmRWZUbVaK9 SpL7qbr+BwMCweVnv2EC0AD/0ZzV/9F9qVc8P9kwBXsL2PZTSMLTHPlv9Wp4ny9X LH13AjR8+SbiX+FZxjBqYMfzQE/vMoSDgrOqEwToZM+K8Xczitox+LQ1YWVhZC1r ZXkgKHRoaXMgaXMgYSB0ZXN0IGtleSkgPGFlYWQta2V5QHByb3Rvbi5ibGFjaz6I kgQTFgoAOhYhBLTRCn0YEvaHOC8wd5z6DYBV4wK2BQJiqJjzAhsDBQsJCAcCAiIC BhUKCQgLAgMWAgECHgcCF4AACgkQnPoNgFXjArYTOwEApydkVgypRciM+4hOw4e4 JrPulK90nKTt/ETH1idPicIBANke01I2pKoTj8dmzq5imE4+sDsKGNEdiksEYMqd Da8BnIsEYqiY8xIKKwYBBAGXVQEFAQEHQJBylc4dtR6ea1yu63TR8+tRpfGxIBR+ 58mXXJ+yfX9dAwEIB/4HAwJtMIaMnD5Nbf9BohXuc0kph8vqzqhMhKahUeBD4B+P 1Gl4nH3BqyMCBS8bWhuYS5SmFdree1nny4aRI+veEB8aCLKDwqvlinh2N/z5Kh2v iHgEGBYKACAWIQS00Qp9GBL2hzgvMHec+g2AVeMCtgUCYqiY8wIbDAAKCRCc+g2A VeMCti86AQDjvVtf8P/pPSpC3KrrKTEZOW+x3mCZJhhUcQkTXlxRTgEArLOPU6kj vWc1uLyrizai9gxpkMZY9oT1BOMkp0wDdgI= =pBZD -----END PGP PRIVATE KEY BLOCK----- golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/issue11_message000066400000000000000000000016471472137411600266570ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- wcBMA4JttJqRS09RAQgAY9TSYXHAT76rrpihX3db4BLnnSjPqWhxysWE8HI6d5tx ZLjxDGE81CO/t0hpokwId7g2GImLHL2LRiwn/V+7AZcF8byX+gIpQsG3TLY/LwZ+ i4FKG7WwZzM50nUNKt6kczvF7QVDd4GLB6GgrvoTvwAhqRGs7EuMHTNAciq7AgBA D6XZbzcG77i367+X6nRLNMujH+CNNlKNKkV7bIQYzHteplQUvDrF+e4+lOOVuc+r ZUKgEyIJrwSUoTU01tJD8M0iRIlKQsBrO7QpjGNna5HDi9dG6UQcKX2wuvkxajHt 3UcPDNjNKapXpshUydnmt6PXnW5IV0aOaZcS9l95SNLAsgGuStjEic6pru368BYO S3j63CG24KiB55eNMdMhZhjgR8ngHDGw/rAWKZKJ0DjI+UV7FJP3GS/y1/KjGEv1 ii7FqPIdiKAUO2f5gtBsstyNmaKpwswP5XP7n9sf76rsoSr2yYSc+nWuAOpyTL0c Q69ln+UvxvRih6x8h7Cbn6N6ex7Jo7p9KMgXJ3gYAOL8WgeF2ZYCrdqNFvH8ManY kqZgnrng8SvTaEpLVIwX8heugVrgT6wdQBpIhmuPIR2jez9Pv8fpg21HHuGId2PV wl7LqgxAWuDBa9BXilR8gR7G6AlK37KUgzAJ6E0/yzQ7RLaECtSzVOZZq6p99tRi SEQxKGd+oTAnsfEm2stTLHblvHxYn2tEKc2pv+v962CoDz4+iNJQdonBaDhRP8jw 1BkzrhNvMZGl9XTO02SUboRufyQsOLq7ba7kmNoLSFOsdj5ugSCAHGFra2zf1Drt jqkiw78nef9bedQ5VMYcQMq7UGo= =zA0T -----END PGP MESSAGE----- golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/issue11_privatekey000066400000000000000000000070641472137411600274150ustar00rootroot00000000000000-----BEGIN PGP PRIVATE KEY BLOCK----- Version: GopenPGP 0.0.1 (ddacebe0) Comment: https://gopenpgp.org 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 =GKOq -----END PGP PRIVATE KEY BLOCK----- golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/issue11_publickey000066400000000000000000000032141472137411600272120ustar00rootroot00000000000000-----BEGIN PGP PUBLIC KEY BLOCK----- xsBNBFz2c2cBCADYDbvxzmxrkjM0EKEHDc00b7gPk8z9bXgEV783Qc+MJZmUb2pk VmBaH0d6ldJ9djJY1ljfBOakn4fGd623uYtgEJKxSQ0FiMwFfiih0hYJ84fmW7g7 EqGlnk9dBzjYWXAOqpkHSDJlAB/rY6jKsAYgVmGQqvdF7SWST512WGoSC4A6sMIC KuNmQNMQ3li9O02wNgvUlZjpn7LBGuoCw9aHjQ72MXSnd4gwt6ds48A5zcXKc8ML TRjo2BIKli+MPyFW9uATfYFkv55KBIFk7JHL/iWhP4m1CQa9xgsoV1C81oOxUqCf CFqfTQ/xhUsdnhdYhsA+whE5mfTg3Hc2fBpBABEBAAHNK3VzZXIyLm5hbWVAZ21h aWwuY29tIDx1c2VyMi5uYW1lQGdtYWlsLmNvbT7CwGgEEwEIABwFAlz2c2cJEGQ7 NZXm7k/fAhsDAhkBAgsJAhUIAAD2OAgAE23JjWTSiZtVinyXyuUYfG0OEaBVopBz lNp25dTcVEBwK/UCtiVEFfHSW4LExYWMICwQTRaE2ViWGASI//ZZZL1ADozqVrZJ YjaUrX50wIMjpazkTsulEdZ7bA/MvV02yyVczC0slc4Q7D70Ley0UKwDlL+1PGj8 Bn8IWd0yBng+/weLCLN7rGCRXdgTe3K+M5enhOMhMaVXElfkEUYDnNIVs7begOWd NB6RAIF9e2TP9z1daj7qjzmqePq9HkykbZXSrrrQzbeYqKvdHn9PO5Mtsaf1r1DH OhG0FMU//ZyG+weEQnB5cuDT58+GGaf68AgNalN1e83kqJRTVvqiYc7ATQRc9nNn AQgAtBDZ1zTTss3tcGDRllycQlahHjMeDkDZbyk4r+h/D+xiMRhrYkgfCg8dZIef SJTJWfqv3BdppcdhnnSBLjFvsXmqqmPDklUM9SqmKcXRKWvQo8/MgOX4uRQJfJ2l uYSba6dCsCl2qHpgv73PH6BK9dllMPXCcdYZjhvKCc9AdD4rL6iVnsqtHcyWHVtZ JaRQWi40nE7w8idkhN9zG/i0Ty25AnaeYyywiOSmaJm0IYIdbw4FPOnLqrT7jlDF s77w8xrWLog5XLFrK2dW+kUBA9qHaBNQc8nlLOzWUKJm0rDnaxR1sJ9YLT0mKCNW RvjGfsUwhQi2095pXoMvNwjMvwARAQABwsBfBBgBCAATBQJc9nNnCRBkOzWV5u5P 3wIbDAAAJXwIABxmfurNk66yBzlxGmhl9SirBy6RG5amJ08jcSru2LkoNnYHgmQj MY2iLvzC4Qw1Q3Iac3oJWHVKqiHlyVUP4PSCbMDo1HScGfKtFRRDNJmNaxQfvcAv dD4xa4L2rT2/ghKgIMRC7U/3XfRPKL+TZTxV5U90tjyIAPEmf+ZdCwoktrCrEo6w AgC5sfEcCPWww6MFWZNqEs0NvFYDsPOJRMdJFYW7BzhkUUasBbF2qNf7L7LmwnfV V1SvIG1FLu/+kUnZriD28dUYmbJbjb9CfZU+2m/KCkcyj/qacdODxxH0Jirta32y o93mjX+Os6LC02tNBzXtzMLnrpJYDDAfb2A= =vMgh -----END PGP PUBLIC KEY BLOCK----- golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/key_dummy000066400000000000000000000052161472137411600256600ustar00rootroot00000000000000-----BEGIN PGP PRIVATE KEY BLOCK----- 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 XGP4suk8zJsKrEscczTb =HRg1 -----END PGP PRIVATE KEY BLOCK----- golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/key_expiredKey000066400000000000000000000011461472137411600266340ustar00rootroot00000000000000-----BEGIN PGP PRIVATE KEY BLOCK----- xcA4BAAAAAEBAgCgONc0J8rfO6cJw5YTP38x1ze2tAYIO7EcmRCNYwMkXngb 0Qdzg34Q5RW0rNiR56VB6KElPUhePRPVklLFiIvHABEBAAEAAf9qabYMzsz/ /LeRVZSsTgTljmJTdzd2ambUbpi+vt8MXJsbaWh71vjoLMWSXajaKSPDjVU5 waFNt9kLqwGGGLqpAQD5ZdMH2XzTq6GU9Ka69iZs6Pbnzwdz59Vc3i8hXlUj zQEApHargCTsrtvSrm+hK/pN51/BHAy9lxCAw9f2etx+AeMA/RGrijkFZtYt jeWdv/usXL3mgHvEcJv63N5zcEvDX5X4W1bND3Rlc3QxIDxhQGIuY29tPsJ7 BBABCAAvBQIAAAABBQMAAAU5BgsJBwgDAgkQzcF99nGrkAkEFQgKAgMWAgEC GQECGwMCHgEAABAlAfwPehmLZs+gOhOTTaSslqQ50bl/REjmv42Nyr1ZBlQS DECl1Qu4QyeXin29uEXWiekMpNlZVsEuc8icCw6ABhIZ =/7PI -----END PGP PRIVATE KEY BLOCK----- golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/key_futureKey000066400000000000000000000061401472137411600265050ustar00rootroot00000000000000-----BEGIN PGP PRIVATE KEY BLOCK----- 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 0uyeibPdgJTjARMuQzDFA8bdbM540vBf5Q== =WLIN -----END PGP PRIVATE KEY BLOCK----- golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/key_mismatching_eddsa_key000066400000000000000000000015131472137411600310340ustar00rootroot00000000000000-----BEGIN PGP PRIVATE KEY BLOCK----- Version: OpenPGP.js v4.10.4 Comment: https://openpgpjs.org xYYEX6FzhhYJKwYBBAHaRw8BAQdA0Yeb41B5BRI25Dq0z7oRCcImRQfT+WcJ HLaHpd6baGT+CQMI/6uWP8YxbIIAJDKhBYD+D8yTJW6JBtnOISKzPSbTNxOP aQEQz1YPMhZhTBIWZFNXo614n3C7Ak1Q73bv8zsJq0EmRJPNkFXmY1S/B0Lm GM0SQm9iIDxpbmZvQGJvYi5jb20+wngEEBYKACAFAl+hc4YGCwkHCAMCBBUI CgIEFgIBAAIZAQIbAwIeAQAKCRBeNKXxFWm5mDjwAQC6vYacL9/oBZ3Ev3DR l9a//92L8hYrx3Le3pRZhJmDqAEAoz5fPGxQEXdgzI14i7ZdNsRRzyGQh3nL jnGeUJx7aQnHiwRfoXOGEgorBgEEAZdVAQUBAQdA2yQoAO2pqLJe48Wazz6+ PSxyh5EXGQZ9yy/ZO2y8Rl8DAQgH/gkDCJE4VlUHrTStAIYCzED5f7BXphR0 jqbMnwTxXxFsI7H9kUykmOPjzYayTLkp/Pw5OMzxjwVKD6+zO4YKtd9EuhEH pD32k72LbNPYE/j3p77CYQQYFggACQUCX6FzhgIbDAAKCRBeNKXxFWm5mJa3 AQDZA/yx5SotHacjZmJir/ly7aPdPUv4krqx86BHbl/2HAD/YSPzjDxBYUDA kWK2+FnnoMBGL6PIKIHlxONRrDVknwQ= =IsER -----END PGP PRIVATE KEY BLOCK-----golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/key_revoked000066400000000000000000000045131472137411600261630ustar00rootroot00000000000000-----BEGIN PGP PUBLIC KEY BLOCK----- Version: OpenPGP.js v4.10.10 Comment: https://openpgpjs.org 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 =iGbb -----END PGP PUBLIC KEY BLOCK-----golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/keyring_privateKey000066400000000000000000000070071472137411600275300ustar00rootroot00000000000000-----BEGIN PGP PRIVATE KEY BLOCK----- Version: OpenPGP.js v0.7.1 Comment: http://openpgpjs.org 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 qqGRQm3MxoTdgQUShAwbNwNNQR9cInfMnA== =2wIY -----END PGP PRIVATE KEY BLOCK----- golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/keyring_privateKeyLegacy000066400000000000000000000070071472137411600306550ustar00rootroot00000000000000-----BEGIN PGP PRIVATE KEY BLOCK----- Version: OpenPGP.js v0.9.0 Comment: http://openpgpjs.org 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 PPekG4ttm6z3/BqqVplanIRSXlsqyp6J8A== =Pyb1 -----END PGP PRIVATE KEY BLOCK----- golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/keyring_publicKey000066400000000000000000000032421472137411600273310ustar00rootroot00000000000000-----BEGIN PGP PUBLIC KEY BLOCK----- Version: OpenPGP.js v0.7.1 Comment: http://openpgpjs.org xsBNBFRJbc0BCAC0mMLZPDBbtSCWvxwmOfXfJkE2+ssM3ux21LhD/bPiWefE WSHlCjJ8PqPHy7snSiUuxuj3f9AvXPvg+mjGLBwu1/QsnSP24sl3qD2onl39 vPiLJXUqZs20ZRgnvX70gjkgEzMFBxINiy2MTIG+4RU8QA7y8KzWev0btqKi MeVa+GLEHhgZ2KPOn4Jv1q4bI9hV0C9NUe2tTXS6/Vv3vbCY7lRR0kbJ65T5 c8CmpqJuASIJNrSXM/Q3NnnsY4kBYH0s5d2FgbASQvzrjuC2rngUg0EoPsrb DEVRA2/BCJonw7aASiNCrSP92lkZdtYlax/pcoE/mQ4WSwySFmcFT7yFABEB AAHNBlVzZXJJRMLAcgQQAQgAJgUCVEltzwYLCQgHAwIJED62JZ7fId8kBBUI AgoDFgIBAhsDAh4BAAD0nQf9EtH9TC0JqSs8q194Zo244jjlJFM3EzxOSULq 0zbywlLORfyoo/O8jU/HIuGz+LT98JDtnltTqfjWgu6pS3ZL2/L4AGUKEoB7 OI6oIdRwzMc61sqI+Qpbzxo7rzufH4CiXZc6cxORUgL550xSCcqnq0q1mds7 h5roKDzxMW6WLiEsc1dN8IQKzC7Ec5wA7U4oNGsJ3TyI8jkIs0IhXrRCd26K 0TW8Xp6GCsfblWXosR13y89WVNgC+xrrJKTZEisc0tRlneIgjcwEUvwfIg2n 9cDUFA/5BsfzTW5IurxqDEziIVP0L44PXjtJrBQaGMPlEbtP5i2oi3OADVX2 XbvsRc7ATQRUSW3PAQgAkPnu5fps5zhOB/e618v/iF3KiogxUeRhA68TbvA+ xnFfTxCx2Vo14aOL0CnaJ8gO5yRSqfomL2O1kMq07N1MGbqucbmc+aSfoElc +Gd5xBE/w3RcEhKcAaYTi35vG22zlZup4x3ElioyIarOssFEkQgNNyDf5AXZ jdHLA6qVxeqAb/Ff74+y9HUmLPSsRU9NwFzvK3Jv8C/ubHVLzTYdFgYkc4W1 Uug9Ou08K+/4NEMrwnPFBbZdJAuUjQz2zW2ZiEKiBggiorH2o5N3mYUnWEmU vqL3EOS8TbWo8UBIW3DDm2JiZR8VrEgvBtc9mVDUj/x+5pR07Fy1D6DjRmAc 9wARAQABwsBfBBgBCAATBQJUSW3SCRA+tiWe3yHfJAIbDAAA/iwH/ik9RKZM B9Ir0x5mGpKPuqhugwrc3d04m1sOdXJm2NtD4ddzSEvzHwaPNvEvUl5v7FVM zf6+6mYGWHyNP4+e7RtwYLlRpud6smuGyDSsotUYyumiqP6680ZIeWVQ+a1T ThNs878mAJy1FhvQFdTmA8XIC616hDFpamQKPlpoO1a0wZnQhrPwT77HDYEE a+hqY4Jr/a7ui40S+7xYRHKL/7ZAS4/grWllhU3dbNrwSzrOKwrA/U0/9t73 8Ap6JL71YymDeaL4sutcoaahda1pTrMWePtrCltz6uySwbZs7GXoEzjX3EAH +6qhkUJtzMaE3YEFEoQMGzcDTUEfXCJ3zJw= =yT9U -----END PGP PUBLIC KEY BLOCK----- golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/keyring_token000066400000000000000000000011531472137411600265210ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: OpenPGP.js v1.2.0 Comment: http://openpgpjs.org wcBMA0fcZ7XLgmf2AQf/RxDfA7g85KzH4371D/jx6deJIXPOWAqgTlGQMsTt yg4ny3phSC2An/bUXNEBm8UMXqqtS7O+S8n1GjkDrCOkxyC+HugOFQwtybzI eRX0X0qqvR6ry940SNGjPfJJ4Z0FYSLJtT8YxqO38t38WAYV1j9mBBVPMPJF r7cQXxEcQAd6NZWF1Cf5Ajuum/zFjbA10Ksbi1tC4fsdtHcS94h1GCfsdNQi xxbAuoyNYX2wsc6WX8IcmDNn564ZoHfvf2tX4Csf+2czByyOPtfyCn1aee51 I40/I+65w8NfYEfzu7pbUcdo041Xg3lOhDNcuX/zANNw6zEWbE+12G5KVvwC NNJgARWnwnOKtov2d73wGqNawn21SzA+zEd2mAPv1LPPIupW+0xOUSp5muov aLEjcIuZeu+vyhXGZxIgoY4Bw8XCO9uWKZuzmqp+AOIP+kSi5aWnOaDFIOq0 B3KtZ33bMZeX =mig5 -----END PGP MESSAGE----- golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/keyring_userKey000066400000000000000000000066741472137411600270450ustar00rootroot00000000000000-----BEGIN PGP PRIVATE KEY BLOCK----- Version: OpenPGP.js v4.4.5 Comment: testpassphrase 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 uaSC3IcBmBsj1fNb4eYXElILjQ== =fMOl -----END PGP PRIVATE KEY BLOCK----- golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/message_badmdc000066400000000000000000000013031472137411600265640ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- wcDMA3wvqk35PDeyAQv/bxxV95z095aN6D+s6ayatoZc2xakyZenaCYiDIY26CmW iLmzNHasoPAmKa3dN3diiMuquKQLJQEoAeAd0L5xDwi7nTpan8E7F9p2krP+hGGy bNaWez5O0Eyw2D5VPokybYIJ+bLo0MEZ/DOzUQ8HijDt2pPQ37CJP6jhA3rcFgwb pEEjF2zWwI3PLrVdO8XcBI5y34ZCUO94FzQUN6/xVpeFQ3vlc9mOajv03l+wyisb 4UeXbSJMEnZr915UqNiu8L9/y9BwVtZ2StRSiumMT4OPDjRAQMQQL7FcpogzVwPm oCmVw1ZcBltnBtpdH7F+M4+PUaaVZTTIYOxCBa1rfpnIcKefJpsAS7aaFZQUs+8a DxEygVzUF6rk2/WajmefwrZ+7EGWFQU0VfPHXqozDAuryzx7p9jMCn+QnyVvtYkv QqvO1SLa3RqLjqV67QnwCs2lo9WMQDcUchsAC34t1bOtzzqxZOlN12PHn4SyjRdo 74vEv+SPViLjZPfcB3Kz0kwBQump/fZNQys1LvrAevWs+1UIaUhLzb5UmdELsCAY ebkFfoWZdskeR+1qSeui57C4ggOHu0Mm/JCbJxAFAHHn+RE8oQhnYiD6xTsA =cHtj -----END PGP MESSAGE----- golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/message_expired000066400000000000000000000016651472137411600270250ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Comment: GPGTools - https://gpgtools.org owEBWwKk/ZANAwAKAeyAexA3gWZ0AawUYgloZWxsby50eHRaX2WpaGVsbG+JAjME AAEKAB0WIQTxcIn7ZRrhwd51IZbsgHsQN4FmdAUCWl9lqQAKCRDsgHsQN4FmdCln D/44x1bcrOXg+DbRStSrC75wFa+cvPEmaTZyqN6d7qlQCMxOcPlq6lbZ74QWfEq7 i1ZYHp4AU8jALw0QqBQQE5FvABleQKpVfY22s83Bqy+P0DB9ntpD+t+oZrxGCLmL MbZJNFnGro48gHt+/OQKLuftiVwE2opHfgogVKNL74FmYA0hMItdzpn4OPNFkP8t Iq/m0hkXlTAKqBPITVLv1FN16v+Sm1iC317eP/HOTYqVZdJN3svVF8ZBfg29a8p6 6nl67fZhXgrt0OB6KSNIZEwMTWjFAqi365mtTssqAA0un94+cQ/WvAC5QcMM8g5S i3G7vny9AsXor+GDU1z7UDWs3wBV4mVRdj7bBIS6PK+6oe012aNpRObcI2bU2BT/ H/7uHZWfwEmpfvH9RVZgoeETA3vSx7MDrNyDt3gwv2hxOHEd7nnVQ3EKG33173o1 /5/oEmn2USujKGhHJ2Zo3aWNRuUWZlvBaYw+PwB2R0UiuJbi0KofNYPssNdpw4sg Qs7Nb2/Ilo1zn5bDh+WDrUrn6zHKAfBytBPpwPFWPZ8W10HUlC5vMZSKH5/UZhj5 kLlUC1zKjFPpRhO27ImTJuImil4lR2/CFjB1duG3JGJQaYIq8RFJOjvTVY29wl0i pFy6y1Ofv2lLHB9K7N7dvvee2nvpUMkLEL52oFQ6Jc7sdg== =Q4tk -----END PGP MESSAGE----- golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/message_mixedPasswordPublic000066400000000000000000000033461472137411600313530ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: GopenPGP 2.0.1 Comment: password = pinata wcBMA8qvclb8pUGwAQf/XTPYYr4JvanBwmEPVk7ej5dA4jIWaip0TGzCZMzgiD2A UVsCKDSbPRHbtAS5xMWcESz1Bjwnn/3BG4kLRqiSSthI1w/1MDv126UsM+4Yo3hD JO+J2EeUSYyXmeXHsSfZxs/Ip+oo2QQaOLvnX1SJAaDk6g4/8A2vz/0sEIGcsaJZ sGnnUbi2YCQ09Z7hpNihaKTXWeCey3OQhRQAw8Y+tL8U+pfL2GF+kGYSv8xj250Z nafO1BdmhvNBAcNSdqJZ8f7J3iINNOejmnyvmg854hU5m8ZSm3uYvVUS4pZsxW4Z djni0zn+akHBhg+imiCvMClFep6a4iiKXY0GX4OB+8MuBAkDCCBAYrwoW0Oc4MiS evR8lScfSANGprwSnJsehqLQf3N3W9nyltbhhi/+vtLCwQGiyBA9Ercz0r5Lcv7U 2bi3KovO317GDZar+O5/Hzq7nyd8rbe8U+hQMF9+Ga05Z4al2KB938qhV0LJB03u 3c07tfXvOf2whTJ2LlaSlWg2CSHSsigGGkWe25gqHN8QfEtkDnllz6h1kgcZcluf 2Tp88dcTpftPeHDHhFGe1+Vnyzc22vdZoG7Pskrd83PtkJUbmAJnkvdNeHW11oJl POWPskyh4kdywOxcnV8qcGBZ8H1dcFnNEwMvhGPgh1pcTisUjRX+ZDzaVU8AXlkk TeFjASY/B0Q2HvX0g+uJVzzymPxlK7mGmFe6uHo/vBGO8gxtnHy1DtJ8fVAeMF9/ VxvK13eN9Ra5y95IcF6XEmGjgdmHUnGHbfiz/ug4suuGiJA7MWnCHSwYXzGxe6Hc tvyHxsQcwaObdEtKtBLHc6M8Em5C89iy72sJuevx4QU9EM3ra+JSCC/3oSOsTCJy dOI29cdAvuApVJySXFhjTDZxVhlSOlFCbMsNFpLXzK0q01jaK+algugSIMvr3XaC PTm1GXUBhw4o6qz3apFVwg0/JrhIidrsUSmV1VOBSOsLW+RZhoyA/g4CekI6tFAx yx+mTsRvKv+OR33QkdXWhoe7kAOM5qbAE5v0tlUaf4f7WN2w0p1YSaRovSGgig7d NMKVGukIhB5mC2+dB1Uzr/FUHMNf1Cm4YXBiSRVXUryN8GSywBaX0Cnk1WrNTlYZ OZifoVaBvi/dGSF4GlE9q3BQY51LTB+tWR7zJk343mXcpwC++7rRmr0C2smc/fOp Ok+KiHDCkWdgdRRV6uBGR1j5037ytJWbB6ETLF/13p5UcZnTYTC27cSSUG0Jt+zy xWs1HnWT6Z9CpEsW+d+W8MWuUtS7YEsLHTmd6Vf1lIT0EwRqtXOfkFJeYpvFlxOK OINYKbhSvKFrSoOkRBtbI2YFbZLZDIgRZEc/oHdu+/O6td1203+ehxGoDyzbWYWh 8hh7MI98SQBxwiir2B+04AEdl4mC3LFIJr8HQK3He54Gf1g4Y3uvCcclB0sRnV5j CyYRXt+eE6SXgbm8vqWmyqetM7LpKGE+Z19qbBdd+qlupWJcBZ3Bj5q4Bmufloif LeifnA9RUVSM5rS/mTzH5A/bZegeifodX3m69kuNiYxSlzzeoVQaLURsNJVYrsli gT9xedbgCYAJLKtf7HhaQu1TSQ== =W7AQ -----END PGP MESSAGE----- golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/message_mixedPasswordPublicExpected000066400000000000000000000010411472137411600330230ustar00rootroot00000000000000"ukm=z7ף"ZIq E52I:b3~ʇdQ'EhJ[پv#6Dgj HډG`FGLNe8u9xJ0 TVyM[U">5/Ϟ-'V?O]**GDRG 4 aݳ8H`m' MZd,ҟ9 (%ɆDZ:XY3\0<ɌcF{fHYy1k(mvgK6ar8Lі|Āi>%, M~"30t6lIMd_jeej saas

Sent from ProtonMail, encrypted email based in Switzerland.

golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/message_sha1_signed000066400000000000000000000023571472137411600275510ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: OpenPGP.js v4.10.4 Comment: https://openpgpjs.org wcBMA0fcZ7XLgmf2AQf/SRGI1T68u5cqeSbznX2T8mpHliVIXj1Oifa1cqaA spPxpuFMYctAS1J3yOVaFMtNSlFaGR3ftQb09d1Lx9JXW31tshWO+7EAZ44j yqS3y4KUqJPm9W73UIEUk0z49fiIDAnOTfMkSai1Y1KtSUtD+4ZRdkYRqEV0 WfUlExkjDu98aBEzr4GPMefl8+VC17n6jOpOikT1rUJbelOIhpW2T9sEy0mw X200eaiVY1Ge9OTOEpLxY+pmFfdVZpmoOzSCn3C3uxNPT5uDzwBqFBUOAJHA oZNrZx67Nl/swa+Y7Mcr4z1iIMKbwn37Zk29zzat9tfJRhDTAOk/6Z5KjOPB qNLBeQFoUgbkNmoLDEbi6EYU9POQxkovnIfBGhJI5XkJlh/Dqe2iaysrNIHv JIhtqZ1Zq3NNsKdOsfCTkkQFZwJc8gsK72aRXPDMn+qXm9O6Tv3qXZL+Eewz +RT+OI2xtc44xpY6tLPTmNYlVyqGC2yAUIbFeqct3A/98g1uZn617RGtHBiY ql1L4YeB/3mJpY4pK4Syota95vbNhJo5Sai9qnh+KTB8UlEbjmg6ULdH2tVG F7ET/IbjCs1D2wgdjs2fn/TIpO5sbVjo4VmxxnYdWWvf36r7QTmHXh1mAkKt EqSxQg/VUaeW/ew41zfO+xYJLGnpkvgcfyrzgHqrq0wEMe/+V+r8s1lRJ1NC 8jv6vEyhH/cS/qTK7zhs8rS7JB0ywefuJKyu3XcBUSceQOmwG7GqhXkYYaAT yscUK82tOxw562ccxxgXtQ11EXrJw4+lOe2hVkp6y+MRYGFQY4VntpnxbrpY gPikwUOpDXbluzzn5pXgKXsMfdhxcYLL8NaBq6xMLRR+MNoO+fQ8WVR7HWcE BdYLl4vRXdwCBW1Bg1ndmF050d6otcPHZ54xaEqZDugtv3schPrqXaNSGMg3 DTceof/a4KUaAfJxpP7BfCTrFu+CyLhNMS5RUeKNVEXxmXnlF6g8x6gEKbJA ave6M75z/Pluqpz6ZtYxKJPsutX4WPoGahY/Gu6aRkp1RcE7VFsSlv2sZq4A t7zowuG+7Y+PdQzOhNkxs17D5vhjJYqF+rmFwQ/TU9V6 =nhYM -----END PGP MESSAGE----- golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/message_sha256_signed000066400000000000000000000023571472137411600277250ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: OpenPGP.js v4.10.4 Comment: https://openpgpjs.org wcBMA0fcZ7XLgmf2AQf/adxZ10qXLL0qVcYq7iDTpGNEKbR8UWcWqN6S6GnG XJwVretWIGLjJiPdh7irZcG993rCJr43P6uZg8AD/+7G/ceVFSRw2+dYHZmp bq3e89py+zGO/m3o+41RF+3ekH3LHZsb/x4Ob+ZZM3UqOX9cvFiKKN1MjyH2 JkHWhQLtZVxDKwa77QBvs5fu8kzEdVFjA1RQhRbQpkuTMkfOEfcsuqHrWJrG T2eliNU5VzIBxfojLOSAF1ueMP3QMrB/vMimEnO140MJHf4mwj92+a9BxyXs UAbgKC79BsrF5CsND7+ANsoTJTv2eDxf6bVEfCk8HwT5X/C4hOgJ9ILOw8K2 Y9LBeQH9RMVQej1Az9glJY7S3FlTL9IUndFPD5Mb/+zNjNv6Mg5UquxmeZZx S8RJDjAOTC2Rcv9jlELh6leS3meY+lpXar/ao+FL/1eB8zKkGsZqstfhmA14 S5I5R4EgLmjkt+Ibg3Kj2sswWchB9eDdfvW/VwrhXU45Hv+EeKS/Pn+5qf05 E5j7PQ3+EtdMTLIT3cSJe1a7zHlLR49hAzJ3Z5wPSmIzFYNE7RvnRA/7MMv/ amlHAdIjDejDFIHR4LsT5e0GyMcAaDAOyGZRxM9fPo7PmZhz7mvoY4MGaBZ/ icrv91IunxWo7QjLzubx4lVJM6xi2375Mntk4ZI6JNTblodOXEchTCmzNQxE jJkzLnlMU8/gTNLJh43pgy2F8+QVYjqZT61mnScBIUidQVNeqSOiHyLCsAgS Q2XAzIgf7HO+UBqHfrDG9wtNtUKVRrGhMwNiVXIO8VvdrKsYrWdmCgvKXZn8 cdS9991BJQSavQRjf6rZRit+4iBzx3elYOtdN6zu3JrF1Mjm7pgDfij8Z1o1 2hpUDNWPCa1idijPp9wvy03lXuVhB1U+rFb+ASslYoXyOASiZuKGAyxXaJwR 5VOY1EKExsSzh74w2bvtFyO/BjF5OFqtL2j3CEu3CWPiYlFPZzF+/jf8v/QQ jfB1gs9u/Yz9ao9BU00eooLud3cS5mr8jeO/ugKh3rAqQEShsmoillyuNWlr Dusky1Y9txR4llJOdcdIyhMhnUdMd8yVF4FfhlGgVirY =oTYf -----END PGP MESSAGE----- golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/message_signed000066400000000000000000000017561472137411600266370ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: OpenPGP.js v4.5.3 Comment: https://openpgpjs.org wcBMA0fcZ7XLgmf2AQgAgnHOlcAwVu2AnVfi2fIQHSkTQ0OFnZMJMRR3MJ1q HtUW8jkSLcurL0Sn/tBFLIIR4YT2tQMzV7cvZzZyBEuZM4OYnDp8xSmoszPh Gc/nvYG0A0pmKAQkL27v05Dul8oUWA0APT51urghH2Pzm7NdOMtTKIE4LQjS mBfQ6Cf14uKV0xGS9v2dSFjFxxXEEpMQ+k60NCKRYClN2LVVxf3OKXbuugds m2GUGn3CuFsiabosIUv4EcdE3aD9HbNo+PIWLJWRJIYJSc5+FWcbwXuIIFgC XX1s7OV53ceZJnhjCmDE0N2ZOLLAYWED2zRvUa+CAqG+hZgc/3Ia+UmJUVuZ BNLAugFuRsOVgh3olUIz0vazHhyGG0XIsNqmRm0U9SIfhWkPPHBmU6Xht6Qw EvLbBfKTYHxX01yQUNgIv4S/TULeQuUjZQfsNYNXXGepS+jiCoIdEgUwpvre OMFGsypwQXVCFYO/GQdYanMQRTckEexyBY4hGYVrevDM1yG/zGJIdbfI2L+1 1cz76jI8PtzL+S0zcVkevLcjjsHm2Je959uSida9jara7Bymr0y56UdoXoWX 4vZ0kQNo58eEEV0zg7dit4lDvwcuSZMW6K//xNtRQ4QX7/EDtlcYqBJXPwJY eQSBVeYbeUbZ+PHJdu5gbI85BJNE2dKcS1bdOhEU2lPLYpvmMpPdot9TwnJb dN3l8yDyhScGvTIZqlxhU7HCM9VHAS0bDqCUoO8EruztUSgjMI+gKC9+xdVU yrkF7K23UNLWflROMv4cp0LDRB57619Y2w5lY/MG5bS0jSfMWBwnJG2AF28c 2tYKnHw6rpZXvXnlDmEDT8suTzuTGA== =Sir8 -----END PGP MESSAGE----- golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/sed_key000066400000000000000000000117741472137411600253060ustar00rootroot00000000000000-----BEGIN PGP PRIVATE KEY BLOCK----- Comment: Bob's OpenPGP Transferable Secret Key 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 =miES -----END PGP PRIVATE KEY BLOCK-----golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/sed_message000066400000000000000000000012421472137411600261270ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- hQGMA3wvqk35PDeyAQwAyfOgW1muzY3NhAeShMCUzoAeAY6BGeJ2vCVZ1JCELVNk hxZIapaprHkmBHHlTOeS7r0YUhIoxgCbra1wh7o4qL7LGEh1EhuvXYi+2qXoCcCy 2eGG8F2C5szBee9Jj3tDweevpHCR9g5JixoTrqIyUWhse1IdNyXxw+/CYwTwBiYI 1hEZznYpyxuZPpcZ3aVtF+keIQRizzItjEs9+plUlelASmuhN3RqvUImItqsBG4r X3Y0wwHxbAg/m+7YasU61ikFYh/Dt5n9OVZ/cOwypAu/7lMrfkMqf41oJcoDvgr7 7JL/t68OlVmy9BxgFvWvtNenF/zdW0hNmko8JXEUZBG1b9gKvYCPVQ/sJdzm2G4n U5hiGUu0l6cGubcf4hrDUTRROXfKUwrkPNxSBpBy9iqZFFqKGX4yBy2lfuRfZaTa gfTLganwio32jXHFdrAMnyn3vqogFKM12ZIhdxQsYNMb/4SUW5L0Jun5hieAqchE 3e4bbBzLwBRyRkonYnRYyTJPzN/SChiPO3UEA0U55pDYBrqH3Nv5lSbeXiE31pXW 7FZr1phe3LZVUso6CUzJdyECJw== =meER -----END PGP MESSAGE-----golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/sessionkey_key000066400000000000000000000033701472137411600267200ustar00rootroot00000000000000-----BEGIN PGP PRIVATE KEY BLOCK----- Version: BCPG C# v1.8.8.0 lQOyBF/H5jYBCACIUtGN3wGf8I4Kl+fwz54nrJcPYf88hyUDNOY2esSBqd7RrJCU RrWFKmuYHXdstfLwS9h8FLboLB5Gkq+hNnWq66CFC3H93rvmvm8IEU3DcJyUSIMr QlQn4+/lsMhHjerwhHJrY/moNaDzZ85WEvnkbptEy8AUJLw0t8wMbujyUfdQnmCK CRTB/s/Ol9gq+eRar6YPonr/8R/YM/kColk+7VKENayslb2217X8SZ99MzeWbafP 9JRq/sl0dAfYH0Gbw+1tTyP5lB5LAbdZ0OVYPW0tnJ9yKjDBjrwn5C/3hDS4fYzk FZAix1baNBuqtgRUzCnu0AjZW9LfFrZts6aVAAUT/wkDAsUlnOW3SOQLYLnYo/Td zOwk7Myzttd++zQ7rCZOksGFk3qVJOA18z1CKMKg/NB+hDWpw7gw9HejnnFOxZ1x ONCQ09x7/nrza13XiLGoeOCgIz4VKkUDiup1l4x9/9P6jVNwSmtSdzgVb+4lv8X2 YFkt3o/SxlztM2s9ZiFz2IBXMF4FgXogG9417RmXKJc0Ham5rZQ0PEVWqCVmXcPq pbb5z/TgwfScAzpKvjFXusR7s+jDYk2PZ8NN4ncOlFRSXOEBTJ98hyx0A520Kqkz NqB15SQRIUIwbpsHud+bEYS5jfEMb1fg4GAr/lCeu++g4ckmFeoehSUTRLiQcpZ8 8iVUrF5VJqj3D4h6hJPaLplA1uqA29cVo8c1OO0RUtOnUEi4MRoGDyf2kFHcKvqk lPnb+UxeBI4LLiUWcAKGEHIZujTWfwvfJdBFM5aDZbHFAi7YIX7OBSrQPpa/3uSK V6I0jJWtXGw693EQ9BGdlScHp4/iSdSb6cjHjTxqe/jJOadnY5OPb+mHSGs/AWQ8 4dGERmjRE9nfV8Pau1/3Hk7h5ELjDrDu3X2t4Gc/U8I7I1kWywmQbxJVvfsMjZio jOBnaBigjWT2sEFyvgNd96IEpWBIlF25y7AaR9f1oe7INzl0I48xXjyb8JPZyLU3 9NbWob6MscqQw9ePai/xCeXS5VUYc/VqAp2SYrNuh5YFh52arWjABPWcZxAOSRmT OTXf8Oqs4XINYK2uuu25DMwAA7Y0NTEUYETkSOJQ0hrs+vXDabIJIunkr9V4o5kR l8ivGEFvKyuq4djPgINbybwtKg5wDAupik8x7vipiGNmkrICDJOaUqhy/JU+QXrU an1BvMoFz4bqI2yhjV5OqgLpZFJIoirWb6igkkMhXzbThtq/HrQAiQEcBBABAgAG BQJfx+Y2AAoJECkFqdVSI1GtKtAH/jzA+CkPkSaN6A29RP/BWSRSeCEMP9+ihrhh AZ2xZYUgeUnvv/UMqI6oq6ytvttMJYlaF8sRVLy/1IPCs3j8uHwqYZTbrfU3U3pC 52NoalCzYV82QM1RViiOO+yYuR7uR66ETpMmKzl3J9l78756Ti6aYU/mY06QQLc7 5iGmjv0vQTGLnrmTR60PBWoC1M66v/keJg1caW0o05dQCDScP8TSA/VhDyf2Sn84 RMNkzQymCb/PpUcDbfcM/7izOsn1A/ypX3p1B7LRr044QylxjrisM0Yyk5ATHWkU s9IcG0hCAeASb2stvyioO4GMbelxFOdfDh/2bEWlfUYIMnDToHg= =grHo -----END PGP PRIVATE KEY BLOCK-----golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/sessionkey_packet000066400000000000000000000005541472137411600274000ustar00rootroot00000000000000wcBMAykFqdVSI1GtAQf+ID+pqYcKMsHUeos3qQ/2zJ+8XguKg8/bpW66XXQJOlXO/yWP5NplcuBIZcDfnJ9gk8cpOg8QXCzgk4BqmpuDVrShn0M4UnmcISC43i5L8+tS63Vv0LHxdcj5ADYAFKz0bRKjhf3JFjibttn8nuEEJJVNi4zUwC2lVr8v5THxj6SpZtNrBeFaaQ0Y78q8rNqPZtNqq2TcCmlVj4d+VnNnbkEOrizw97I9P784L169s0kVb3S0t0r1Y/mOPxq3T1EXDbo37quveZjKHgkuT/1FTOEO2yzqPOhyRlF6MuQYlPJMZv9pHwNDCyfm8WQutzpRK+MI4AcqVyALC4rU3w9JNg==golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/signature/000077500000000000000000000000001472137411600257275ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/signature/critical_context_detached_sig000066400000000000000000000011221472137411600336670ustar00rootroot00000000000000-----BEGIN PGP SIGNATURE----- Version: GopenPGP 2.5.2 Comment: https://gopenpgp.org wsCaBAABCgBOBQJkBdTjCZA+tiWe3yHfJBYhBG6LoimwzMr2li+XlT62JZ7fId8k JpSAAAAAABEADGNvbnRleHRAcHJvdG9uLmNodGVzdC1jb250ZXh0AACmMwgAmhVy MIOgqeidOgNUQrOren3m53sA48dO0xmSRMd1HZa4uv5gDDisl+j98l7iawpvnQ1m GqMvvrxyCV66h3W1efjGCW8lbGMKjaSZL4iUteRrAYCfsBq2l7yMDqFn+Kqns9f5 c29eh5mSxiGtmJsGSoJVFw7ZfDS+QpIw1yEsdYcyKLqdxmFS5pNQwY8uGuCrPaya 4iHLP52kGRt9pTSQTf8flwjb1bjTTJ/dOd3C2AVXtH7NmOgtLeLuc2bT6WKJFPwd BYgCnD0r/6bcRqzqdhcV2lK3WtG1AitH0kKweXhPbtv9OGD36//04zGAeZY7BK8+ 4J2lzLNX+pYtHPbnRw== =XIJE -----END PGP SIGNATURE-----golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/signature/detachedSigSignedTwice000066400000000000000000000006061472137411600322060ustar00rootroot00000000000000-----BEGIN PGP SIGNATURE----- wnUEARYKAAYFAmCCo8gAIQkQyQtnL+EYbekWIQTopSabUSqDUEv/FMHJC2cv 4Rht6VeGAP4mUJl+WYN9nLE57YByTh95OmcZmwfgz5Z4R570YqTVngD/VBym icc7YREcxij1gC6SSAe8kgKW6oVOWzxJ8HkOSQrCdQQBFgoABgUCYIK9vQAh CRCGHCX3YYW5NRYhBErDPc6OYkUaNQCLhoYcJfdhhbk1W1QBAPhrkAjimO22 jh1V2A8pRCOs53Ig/AMAFbN37BaAIEVKAP0SVMTL6zTxYJcxWNPog7Bv5lM4 Px4G+hZ2Kia//qlgBg== =0aeU -----END PGP SIGNATURE-----double_critical_context_detached_sig000066400000000000000000000012071472137411600351460ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/signature-----BEGIN PGP SIGNATURE----- Version: GopenPGP 2.5.2 Comment: https://gopenpgp.org wsDDBAABCgB3BQJkBd5+CZA+tiWe3yHfJBYhBG6LoimwzMr2li+XlT62JZ7fId8k JpSAAAAAABEADGNvbnRleHRAcHJvdG9uLmNodGVzdC1jb250ZXh0KJSAAAAAABEA DmNvbnRleHRAcHJvdG9uLmNodGVzdC1jb250ZXh0LTIAAGnMB/9Z9Bd0z9Q6gvBB xxh2v/p9PleBwytUbUMaPrL4gzRsfsKF/9kShY9ZCYpzFeTVtTHGG2C8rEiCPLev 01xr3wxVq5N8iyyF9H839qwsAKomkNrqpuAtHHF76uE/vpnqRLQ+2eCiTyOh/BSH syizwNBRaYeVtabZVXGW5ofWFoq/sgmO4Pr63hPiTmhFbIWDOZVadN1rHOVaLBPW mlcxb7vK2FUdcyIpwsQMH9ReDNe2FiCLy/lTWyKFYO43/6VnzHtd5Gn1MXLm2tuN zMTEGii2WFPH8u0e6sQCcmkhJS44J8y2MFv6BKrZKcRpZfzOLPzktBvFg7Q9Pvo3 1qxluPe5 =KiYX -----END PGP SIGNATURE-----golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/signature/no_context_detached_sig000066400000000000000000000010351472137411600325140ustar00rootroot00000000000000-----BEGIN PGP SIGNATURE----- Version: GopenPGP 2.5.2 Comment: https://gopenpgp.org wsBzBAABCgAnBQJkBdkOCZA+tiWe3yHfJBYhBG6LoimwzMr2li+XlT62JZ7fId8k AAAwOgf/U+wgABHyfI6Bd/1xPdUyy3FTaEY+Nj8NYi/PKez66OmLubgMEj0DfD7M 2P4SL3ZR0Y9iEtCKpncvLtlvA0sss0SZMaXH0bpJZS62cc98gLBuhE9mP1aWUu1u +1AKVIvJKzhJC+MjKrVwMO03JrEb97ZDJylqoF2UvTeQomIY6qo5l4khDeZRVgsn wqmq7+FLGHG75bhrW4dSOCKrNdKwodml/3l4/R8OPhRL6882egXfBtF0i0yhnX2s 4watN2OKQE8b9gfkrDWp0vA/hLLXx8IdIiuAkj55Dj6ciVXy6fTfKqcK4/IIX4MO y5KD4MLQbmTja5KoK82mavsbhwXM7A== =k4Xq -----END PGP SIGNATURE-----non_critical_context_detached_sig000066400000000000000000000011221472137411600344620ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/signature-----BEGIN PGP SIGNATURE----- Version: GopenPGP 2.5.2 Comment: https://gopenpgp.org wsCaBAABCgBOBQJkBdcDCZA+tiWe3yHfJBYhBG6LoimwzMr2li+XlT62JZ7fId8k JhSAAAAAABEADGNvbnRleHRAcHJvdG9uLmNodGVzdC1jb250ZXh0AAAWswgAmtfD vf7yNlc2umZ4p8ddlcQGhkpwQgiTuaYIeJytAytPtzzSAuMUcACeBCXCTt9iXaak ImnZULdBW6T5n/o5zVTVO5yGniOeswpXqERnp+Qmsowjd5fU+XRBnkx0cSVIrVo5 tB4gf5nxAnojusQekELnNINd8nXrWYHiDFM+aos+pTxqzWlcJv32LtQ4yuxWSzIL 9dJMIpqL+1jk2QI6E+6iTM6NkwNhYjJ7emMGJXyzPmXj4pmpJ1lYo50uHRlwirnI VXcOkUKUwGdibnCjUv+XFoG7Qv2ilDuk/TxTKSjW7ajGjv6KAOde/pOtmpiwcWKi OzIkiswXw5vOtLkrew== =Ub8I -----END PGP SIGNATURE-----golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/signature/publicKey1000066400000000000000000000011431472137411600276610ustar00rootroot00000000000000-----BEGIN PGP PUBLIC KEY BLOCK----- xjMEYIKjXxYJKwYBBAHaRw8BAQdAbmODPSLO5tOI0GxfV+x5bgiiFriCcH3t 6lbJkS+OzKbNEHRlc3QgPHRlc3RAYS5pdD7CjAQQFgoAHQUCYIKjXwQLCQcI AxUICgQWAAIBAhkBAhsDAh4BACEJEMkLZy/hGG3pFiEE6KUmm1Eqg1BL/xTB yQtnL+EYbenOlAEAn7A7RXQJ9FUzhuiOHeKqczdslgOO5LFcng1LuSIWn1UB ANWHrxnH63jnFLE82mfhpRZ5FYJ1fEXA9+3v6at3ZE8IzjgEYIKjXxIKKwYB BAGXVQEFAQEHQA5moGr1AKlYvKI+JpyB6W640eXpQFNSiV6LBjuMteNbAwEI B8J2BBgWCAAJBQJggqNfAhsMACEJEMkLZy/hGG3pFiEE6KUmm1Eqg1BL/xTB yQtnL+EYben97QD4hf6DttxyczHGqxGbboatBZ3IufJgFm6r2xNf9d9lSAD3 U12oHbxyYUhapbFFkSIBo7DWJqWvx3iUEPqzY6jIAA== =ZWrn -----END PGP PUBLIC KEY BLOCK-----golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/testdata/signature/publicKey2000066400000000000000000000011431472137411600276620ustar00rootroot00000000000000-----BEGIN PGP PUBLIC KEY BLOCK----- xjMEYIKjgxYJKwYBBAHaRw8BAQdARyd9iDlrlozcTG144XFIjWozyWLz0KQv fL4lqIrwM8XNEHRlc3QgPHRlc3RAYi5pdD7CjAQQFgoAHQUCYIKjgwQLCQcI AxUICgQWAAIBAhkBAhsDAh4BACEJEIYcJfdhhbk1FiEESsM9zo5iRRo1AIuG hhwl92GFuTVPRAD6A6//tK5pLPa1d7mgsoqyJ9BZyTAmnzxtbIgmOU9/TDcB AI4cGBfCOLzRPw6L0il5Rt78TX1jz4Dlzu6YixJcJ2AFzjgEYIKjgxIKKwYB BAGXVQEFAQEHQMjb0Q1FWvHzj0hyOiEN5ndChBDceUqxmQ0wOYDVqq8JAwEI B8J4BBgWCAAJBQJggqODAhsMACEJEIYcJfdhhbk1FiEESsM9zo5iRRo1AIuG hhwl92GFuTXz4AEAqn4L+ayYgphejF/ZTRIseHPK+t521CT6NZKoVaHnTWQA /0+kMEB5d+CH3Mb54cUganYHPLj5utO2PexEJc3xARIG =IEm4 -----END PGP PUBLIC KEY BLOCK-----golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/time.go000066400000000000000000000006721472137411600234070ustar00rootroot00000000000000package crypto import ( "time" ) // Clock is a function that returns a timestamp. type Clock func() time.Time // NewConstantClock returns a Clock, which always returns unixTime. func NewConstantClock(unixTime int64) Clock { return func() time.Time { return time.Unix(unixTime, 0) } } // ZeroClock returns a Clock, which always returns the zero time.Time. func ZeroClock() Clock { return func() time.Time { return time.Time{} } } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/verify.go000066400000000000000000000044261472137411600237560ustar00rootroot00000000000000package crypto // PGPVerify is an interface for verifying detached signatures with GopenPGP. type PGPVerify interface { // VerifyingReader wraps a reader with a signature verify reader. // Once all data is read from the returned verify reader, the signature can be verified // with (VerifyDataReader).VerifySignature(). // Note that an error is only returned if it is not a signature error. // The encoding indicates if the input signature message should be unarmored or not, // i.e., Bytes/Armor/Auto where Auto tries to detect it automatically. // If detachedData is nil, signatureMessage is treated as an inline signature message. // Thus, it is expected that signatureMessage contains the data to be verified. // If detachedData is not nil, signatureMessage must contain a detached signature, // which is verified against the detachedData. VerifyingReader(detachedData, signatureMessage Reader, encoding int8) (*VerifyDataReader, error) // VerifyDetached verifies a detached signature pgp message // and returns a VerifyResult. The VerifyResult can be checked for failure // and allows access to information about the signatures. // Note that an error is only returned if it is not a signature error. // The encoding indicates if the input signature message should be unarmored or not, // i.e., Bytes/Armor/Auto where Auto tries to detect it automatically. VerifyDetached(data []byte, signature []byte, encoding int8) (*VerifyResult, error) // VerifyInline verifies an inline signed pgp message // and returns a VerifiedDataResult. The VerifiedDataResult can be checked for failure, // allows access to information about the signatures, and includes the plain message. // Note that an error is only returned if it is not a signature error. // The encoding indicates if the input message should be unarmored or not, i.e., Bytes/Armor/Auto // where Auto tries to detect it automatically. VerifyInline(message []byte, encoding int8) (*VerifiedDataResult, error) // VerifyCleartext verifies an armored cleartext message // and returns a VerifyCleartextResult. The VerifyCleartextResult can be checked for failure // and allows access the contained message // Note that an error is only returned if it is not a signature error. VerifyCleartext(cleartext []byte) (*VerifyCleartextResult, error) } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/verify_handle.go000066400000000000000000000214241472137411600252660ustar00rootroot00000000000000package crypto import ( "bytes" "io" "github.com/ProtonMail/go-crypto/openpgp/armor" "github.com/ProtonMail/go-crypto/openpgp/clearsign" "github.com/ProtonMail/go-crypto/openpgp/packet" openpgp "github.com/ProtonMail/go-crypto/openpgp/v2" "github.com/ProtonMail/gopenpgp/v3/constants" "github.com/ProtonMail/gopenpgp/v3/internal" "github.com/pkg/errors" ) type verifyHandle struct { VerifyKeyRing *KeyRing VerificationContext *VerificationContext DisableVerifyTimeCheck bool DisableStrictMessageParsing bool DisableAutomaticTextSanitize bool IsUTF8 bool clock Clock profile SignProfile } // --- Default verification handle to build from func defaultVerifyHandle(profile SignProfile, clock Clock) *verifyHandle { return &verifyHandle{ clock: clock, profile: profile, } } // --- Implements VerifyHandle functions // VerifyingReader wraps a reader with a signature verify reader. // Once all data is read from the returned verify reader, the signature can be verified // with (VerifyDataReader).VerifySignature(). // Note that an error is only returned if it is not a signature error. // The encoding indicates if the input signature message should be unarmored or not, // i.e., Bytes/Armor/Auto where Auto tries to detect it automatically. // If detachedData is nil, signatureMessage is treated as an inline signature message. // Thus, it is expected that signatureMessage contains the data to be verified. // If detachedData is not nil, signatureMessage must contain a detached signature, // which is verified against the detachedData. func (vh *verifyHandle) VerifyingReader(detachedData, signatureMessage Reader, encoding int8) (reader *VerifyDataReader, err error) { var armored bool signatureMessage, armored = unarmorInput(encoding, signatureMessage) if armored { // Wrap with decode armor reader. armoredBlock, err := armor.Decode(signatureMessage) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unarmor failed") } signatureMessage = armoredBlock.Body } if detachedData != nil { if vh.IsUTF8 { detachedData = openpgp.NewCanonicalTextReader(detachedData) } reader, err = vh.verifyingDetachedReader(detachedData, signatureMessage) } else { reader, err = vh.verifyingReader(signatureMessage) if err == nil && vh.IsUTF8 { reader.internalReader = internal.NewSanitizeReader(reader.internalReader) } } return } // VerifyDetached verifies a detached signature pgp message // and returns a VerifyResult. The VerifyResult can be checked for failure // and allows access to information about the signatures. // Note that an error is only returned if it is not a signature error. // The encoding indicates if the input signature message should be unarmored or not, // i.e., Bytes/Armor/Auto where Auto tries to detect it automatically. func (vh *verifyHandle) VerifyDetached(data, signature []byte, encoding int8) (verifyResult *VerifyResult, err error) { signatureMessageReader := bytes.NewReader(signature) detachedDataReader := bytes.NewReader(data) ptReader, err := vh.VerifyingReader(detachedDataReader, signatureMessageReader, encoding) if err != nil { return nil, errors.Wrap(err, "gopenpgp: verifying signature failed") } _, err = io.Copy(io.Discard, ptReader) if err != nil { return nil, errors.Wrap(err, "gopenpgp: reading data to verify signature failed") } return ptReader.VerifySignature() } // VerifyInline verifies an inline signed pgp message // and returns a VerifiedDataResult. The VerifiedDataResult can be checked for failure, // allows access to information about the signatures, and includes the plain message. // Note that an error is only returned if it is not a signature error. // The encoding indicates if the input message should be unarmored or not, i.e., Bytes/Armor/Auto // where Auto tries to detect it automatically. func (vh *verifyHandle) VerifyInline(message []byte, encoding int8) (verifyDataResult *VerifiedDataResult, err error) { var ptReader *VerifyDataReader messageReader := bytes.NewReader(message) ptReader, err = vh.VerifyingReader(nil, messageReader, encoding) if err != nil { return nil, errors.Wrap(err, "gopenpgp: verifying signature failed") } data, err := ptReader.ReadAll() if err != nil { return nil, errors.Wrap(err, "gopenpgp: reading data to verify signature failed") } verifyResult, err := ptReader.VerifySignature() if err != nil { return nil, errors.Wrap(err, "gopenpgp: verifying signature failed") } verifyDataResult = &VerifiedDataResult{ data: data, metadata: ptReader.GetMetadata(), VerifyResult: *verifyResult, } return } // VerifyCleartext verifies an armored cleartext message and returns a VerifyCleartextResult. // The VerifyCleartextResult can be checked for failure and allows access the contained message. // Note that an error is only returned if it is not a signature error. func (vh *verifyHandle) VerifyCleartext(cleartext []byte) (*VerifyCleartextResult, error) { return vh.verifyCleartext(cleartext) } // --- Private logic functions func (vh *verifyHandle) validate() error { if vh.VerifyKeyRing == nil { return errors.New("gopenpgp: no verification key provided") } return nil } // verifyDetachedSignature verifies if a detached signature is valid with the entity list. func (vh *verifyHandle) verifyDetachedSignature( origText io.Reader, signature []byte, ) (result *VerifyResult, err error) { signatureReader := bytes.NewReader(signature) ptReader, err := vh.verifyingDetachedReader(origText, signatureReader) if err != nil { return nil, errors.Wrap(err, "gopenpgp: verify signature failed") } _, err = io.Copy(io.Discard, ptReader) if err != nil { return nil, errors.Wrap(err, "gopenpgp: reading all data from plaintext reader failed") } return ptReader.VerifySignature() } func (vh *verifyHandle) verifyingReader( signatureMessage io.Reader, ) (reader *VerifyDataReader, err error) { checkPacketSequence := !vh.DisableStrictMessageParsing config := vh.profile.SignConfig() config.CheckPacketSequence = &checkPacketSequence verifyTime := vh.clock().Unix() config.Time = NewConstantClock(verifyTime) if vh.VerificationContext != nil { config.KnownNotations = map[string]bool{constants.SignatureContextName: true} } md, err := openpgp.ReadMessage( signatureMessage, vh.VerifyKeyRing.getEntities(), nil, config, ) if err != nil { return nil, errors.Wrap(err, "gopenpgp: initialize signature reader failed") } return &VerifyDataReader{ md, md.UnverifiedBody, vh.VerifyKeyRing, verifyTime, vh.DisableVerifyTimeCheck, false, vh.VerificationContext, }, nil } func (vh *verifyHandle) verifyingDetachedReader( data Reader, signature Reader, ) (*VerifyDataReader, error) { return verifyingDetachedReader( data, signature, vh.VerifyKeyRing, vh.VerificationContext, vh.DisableVerifyTimeCheck, vh.DisableAutomaticTextSanitize, vh.profile.SignConfig(), vh.clock, ) } func (vh *verifyHandle) verifyCleartext(cleartext []byte) (*VerifyCleartextResult, error) { block, rest := clearsign.Decode(cleartext) if block == nil { return nil, errors.New("gopenpgp: not able to parse cleartext message") } if len(bytes.TrimSpace(rest)) > 0 { return nil, errors.New("gopenpgp: cleartext message has trailing text") } signature, err := io.ReadAll(block.ArmoredSignature.Body) if err != nil { return nil, errors.Wrap(err, "gopenpgp: signature not parsable in cleartext") } reader := bytes.NewReader(block.Bytes) result, err := vh.verifyDetachedSignature( reader, signature, ) if err != nil { return nil, errors.Wrap(err, "gopenpgp: cleartext verify failed with non-signature error") } return &VerifyCleartextResult{ VerifyResult: *result, cleartext: block.Plaintext, }, nil } func verifyingDetachedReader( data Reader, signature Reader, verifyKeyRing *KeyRing, verificationContext *VerificationContext, disableVerifyTimeCheck bool, disableAutomaticTextSanitize bool, config *packet.Config, clock Clock, ) (*VerifyDataReader, error) { if config == nil { config = &packet.Config{} } verifyTime := clock().Unix() config.Time = NewConstantClock(verifyTime) if verificationContext != nil { config.KnownNotations = map[string]bool{constants.SignatureContextName: true} } md, err := openpgp.VerifyDetachedSignatureReader( verifyKeyRing.getEntities(), data, signature, config, ) if err != nil { return nil, errors.Wrap(err, "gopenpgp: verify signature reader failed") } internalReader := md.UnverifiedBody if len(md.SignatureCandidates) > 0 && !disableAutomaticTextSanitize && md.SignatureCandidates[0].SigType == packet.SigTypeText { internalReader = internal.NewSanitizeReader(internalReader) } return &VerifyDataReader{ md, internalReader, verifyKeyRing, verifyTime, disableVerifyTimeCheck, false, verificationContext, }, nil } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/verify_handle_builder.go000066400000000000000000000065411472137411600267770ustar00rootroot00000000000000package crypto // VerifyHandleBuilder configures a VerifyHandle handle. type VerifyHandleBuilder struct { handle *verifyHandle defaultClock Clock err error profile SignProfile } func newVerifyHandleBuilder(profile SignProfile, clock Clock) *VerifyHandleBuilder { return &VerifyHandleBuilder{ handle: defaultVerifyHandle(profile, clock), defaultClock: clock, profile: profile, } } // VerificationKeys sets the public keys for verifying the signatures. func (vhb *VerifyHandleBuilder) VerificationKeys(keys *KeyRing) *VerifyHandleBuilder { vhb.handle.VerifyKeyRing = keys return vhb } // VerificationKey sets the public key for verifying the signatures. func (vhb *VerifyHandleBuilder) VerificationKey(key *Key) *VerifyHandleBuilder { var err error if vhb.handle.VerifyKeyRing == nil { vhb.handle.VerifyKeyRing, err = NewKeyRing(key) } else { err = vhb.handle.VerifyKeyRing.AddKey(key) } vhb.err = err return vhb } // VerificationContext sets a verification context for signatures of the pgp message, if any. // Only considered if VerifyKeys are set. func (vhb *VerifyHandleBuilder) VerificationContext(verifyContext *VerificationContext) *VerifyHandleBuilder { vhb.handle.VerificationContext = verifyContext return vhb } // VerifyTime sets the verification time to the provided timestamp. // If not set, the systems current time is used for signature verification. func (vhb *VerifyHandleBuilder) VerifyTime(unixTime int64) *VerifyHandleBuilder { vhb.handle.clock = NewConstantClock(unixTime) return vhb } // Utf8 indicates if the output plaintext is Utf8 and // should be sanitized from canonicalised line endings. // If enabled for detached verification, it canonicalises the input // before verification independent of the signature type. func (vhb *VerifyHandleBuilder) Utf8() *VerifyHandleBuilder { vhb.handle.IsUTF8 = true return vhb } // DisableVerifyTimeCheck disables the check for comparing the signature expiration time // against the verification time. func (vhb *VerifyHandleBuilder) DisableVerifyTimeCheck() *VerifyHandleBuilder { vhb.handle.DisableVerifyTimeCheck = true return vhb } // DisableStrictMessageParsing disables the check that the inputs conform // to the OpenPGP message grammar. // If set, no error is thrown if the input message does not conform to the // OpenPGP specification. func (vhb *VerifyHandleBuilder) DisableStrictMessageParsing() *VerifyHandleBuilder { vhb.handle.DisableStrictMessageParsing = true return vhb } // DisableAutomaticTextSanitize indicates that automatic text sanitization should be disabled. // If not disabled, the output will be sanitized if a text signature is present. func (vhb *VerifyHandleBuilder) DisableAutomaticTextSanitize() *VerifyHandleBuilder { vhb.handle.DisableAutomaticTextSanitize = true return vhb } // New creates a VerifyHandle and checks that the given // combination of parameters is valid. If the parameters are invalid, // an error is returned. func (vhb *VerifyHandleBuilder) New() (PGPVerify, error) { if vhb.err != nil { return nil, vhb.err } vhb.err = vhb.handle.validate() if vhb.err != nil { return nil, vhb.err } handle := vhb.handle vhb.handle = defaultVerifyHandle(vhb.profile, vhb.defaultClock) return handle, nil } // Error returns any errors that occurred within the builder. func (vhb *VerifyHandleBuilder) Error() error { return vhb.err } golang-github-protonmail-gopenpgp-v3-3.1.0/crypto/verify_reader.go000066400000000000000000000114671472137411600253030ustar00rootroot00000000000000package crypto import ( "io" openpgp "github.com/ProtonMail/go-crypto/openpgp/v2" "github.com/pkg/errors" ) // VerifyDataReader is used for reading data that should be verified with a signature. // It further contains additional information about the parsed pgp message where the read // data stems from. type VerifyDataReader struct { details *openpgp.MessageDetails internalReader Reader verifyKeyRing *KeyRing verifyTime int64 disableTimeCheck bool readAll bool verificationContext *VerificationContext } // GetMetadata returns the metadata of the literal data packet that // this reader reads from. Can be nil, if the data is not read from // a literal data packet. func (msg *VerifyDataReader) GetMetadata() *LiteralMetadata { if msg.details.LiteralData == nil { return nil } return &LiteralMetadata{ filename: msg.details.LiteralData.FileName, isUTF8: !msg.details.LiteralData.IsBinary, ModTime: int64(msg.details.LiteralData.Time), } } // Read is used read data from the pgp message. // Makes VerifyDataReader implement the Reader interface. func (msg *VerifyDataReader) Read(b []byte) (n int, err error) { n, err = msg.internalReader.Read(b) if errors.Is(err, io.EOF) { msg.readAll = true } return } // VerifySignature is used to verify that the embedded signatures are valid. // This method needs to be called once all the data has been read. // It will return an error if the signature is invalid, no verifying keys are accessible, // or if the message hasn't been read entirely. func (msg *VerifyDataReader) VerifySignature() (result *VerifyResult, err error) { if !msg.readAll { return nil, errors.New("gopenpgp: can't verify the signature until the message reader has been read entirely") } return createVerifyResult(msg.details, msg.verifyKeyRing, msg.verificationContext, msg.verifyTime, msg.disableTimeCheck) } // ReadAll reads all plaintext data from the reader // and returns it as a byte slice. func (msg *VerifyDataReader) ReadAll() (plaintext []byte, err error) { return io.ReadAll(msg) } // DiscardAll reads all data from the reader and discards it. func (msg *VerifyDataReader) DiscardAll() (err error) { _, err = io.Copy(io.Discard, msg) return err } // DiscardAllAndVerifySignature reads all plaintext data from the reader but discards it. // Returns a verification result for signature verification on the read data. func (msg *VerifyDataReader) DiscardAllAndVerifySignature() (vr *VerifyResult, err error) { err = msg.DiscardAll() if err != nil { return nil, errors.Wrap(err, "gopenpgp: discarding data from reader failed") } return msg.VerifySignature() } // ReadAllAndVerifySignature reads all plaintext data from the reader // and tries to verify the signatures included in the message. // Returns the data in a VerifiedDataResult struct, which can be checked for signature errors. func (msg *VerifyDataReader) ReadAllAndVerifySignature() (*VerifiedDataResult, error) { plaintext, err := msg.ReadAll() if err != nil { return nil, errors.Wrap(err, "gopenpgp: reading all data from reader failed") } verifyResult, err := msg.VerifySignature() return &VerifiedDataResult{ VerifyResult: *verifyResult, data: plaintext, metadata: msg.GetMetadata(), cachedSessionKey: msg.SessionKey(), }, err } // SessionKey returns the session key the data is decrypted with. // Returns nil, if this reader does not read from an encrypted message or // session key caching was not enabled. func (msg *VerifyDataReader) SessionKey() *SessionKey { if msg.details.SessionKey == nil { return nil } alg := getAlgo(msg.details.DecryptedWithAlgorithm) return NewSessionKeyFromToken(msg.details.SessionKey, alg) } // VerifiedDataResult is a result that contains data and // the result of a potential signature verification on the data. type VerifiedDataResult struct { VerifyResult metadata *LiteralMetadata data []byte cachedSessionKey *SessionKey } // Metadata returns the associated literal metadata of the data. func (r *VerifiedDataResult) Metadata() *LiteralMetadata { return r.metadata } // Bytes returns the result data as bytes. func (r *VerifiedDataResult) Bytes() []byte { return r.data } // String returns the result data as string. func (r *VerifiedDataResult) String() string { return string(r.data) } // SessionKey returns the session key the data is decrypted with. // Returns nil, if the data was not encrypted or // session key caching was not enabled. func (r *VerifiedDataResult) SessionKey() *SessionKey { return r.cachedSessionKey } // VerifyCleartextResult is a result of a cleartext message verification. type VerifyCleartextResult struct { VerifyResult cleartext []byte } // Cleartext returns the parsed plain text of the result. func (vc *VerifyCleartextResult) Cleartext() []byte { return vc.cleartext } golang-github-protonmail-gopenpgp-v3-3.1.0/go.mod000066400000000000000000000012531472137411600217040ustar00rootroot00000000000000module github.com/ProtonMail/gopenpgp/v3 go 1.17 require ( github.com/ProtonMail/go-crypto v1.1.3 github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.7.0 ) require ( github.com/cloudflare/circl v1.3.7 // indirect github.com/davecgh/go-spew v1.1.0 // indirect github.com/kr/pretty v0.2.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect golang.org/x/crypto v0.17.0 // indirect golang.org/x/sys v0.16.0 // indirect golang.org/x/text v0.14.0 // indirect gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect ) golang-github-protonmail-gopenpgp-v3-3.1.0/go.sum000066400000000000000000000142521472137411600217340ustar00rootroot00000000000000github.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk= github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f h1:tCbYj7/299ekTTXpdwKYF8eBlsYsDVoggDAuAjoK66k= github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f/go.mod h1:gcr0kNtGBqin9zDW9GOHcVntrwnjrK+qdJ06mWYBybw= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= golang-github-protonmail-gopenpgp-v3-3.1.0/internal/000077500000000000000000000000001472137411600224115ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-v3-3.1.0/internal/armor.go000066400000000000000000000011741472137411600240630ustar00rootroot00000000000000package internal import ( "bytes" "strings" "github.com/ProtonMail/go-crypto/openpgp/armor" "github.com/pkg/errors" ) // Unarmor unarmors an armored string. func Unarmor(input string) (*armor.Block, error) { io := strings.NewReader(input) b, err := armor.Decode(io) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to unarmor") } return b, nil } // UnarmorBytes unarmors an armored byte slice. func UnarmorBytes(input []byte) (*armor.Block, error) { io := bytes.NewReader(input) b, err := armor.Decode(io) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to unarmor") } return b, nil } golang-github-protonmail-gopenpgp-v3-3.1.0/internal/common.go000066400000000000000000000050451472137411600242340ustar00rootroot00000000000000// Package internal contains internal methods and constants. package internal import ( "bytes" "errors" "io" "strings" "github.com/ProtonMail/gopenpgp/v3/constants" ) var nl []byte = []byte("\n") var rnl []byte = []byte("\r\n") func Canonicalize(text string) string { return strings.ReplaceAll(strings.ReplaceAll(text, "\r\n", "\n"), "\n", "\r\n") } func CanonicalizeBytes(text []byte) []byte { return bytes.ReplaceAll(bytes.ReplaceAll(text, rnl, nl), nl, rnl) } func TrimEachLine(text string) string { lines := strings.Split(text, "\n") for i := range lines { lines[i] = strings.TrimRight(lines[i], " \t\r") } return strings.Join(lines, "\n") } func TrimEachLineBytes(text []byte) []byte { lines := bytes.Split(text, nl) for i := range lines { lines[i] = bytes.TrimRight(lines[i], " \t\r") } return bytes.Join(lines, nl) } // ArmorHeaders is a map of default armor headers. var ArmorHeaders = map[string]string{} func init() { if constants.ArmorHeaderEnabled { ArmorHeaders = map[string]string{ "Version": constants.ArmorHeaderVersion, "Comment": constants.ArmorHeaderComment, } } } // ResetReader is a reader that can be reset by buffering data internally. type ResetReader struct { Reader io.Reader buffer *bytes.Buffer bufferData bool } // NewResetReader creates a new ResetReader with the default state. func NewResetReader(reader io.Reader) *ResetReader { return &ResetReader{ Reader: reader, buffer: bytes.NewBuffer(nil), bufferData: true, } } func (rr *ResetReader) Read(b []byte) (n int, err error) { n, err = rr.Reader.Read(b) if rr.bufferData { rr.buffer.Write(b[:n]) } return } // DisableBuffering disables the internal buffering. // After the disable, a Reset is not allowed anymore. func (rr *ResetReader) DisableBuffering() { rr.bufferData = false } // Reset creates a reader that reads again from the beginning and // resets the internal state. func (rr *ResetReader) Reset() (io.Reader, error) { if !rr.bufferData { return nil, errors.New("reset not possible if buffering is disabled") } rr.Reader = io.MultiReader(rr.buffer, rr.Reader) rr.buffer = bytes.NewBuffer(nil) return rr.Reader, nil } type noOpWriteCloser struct { writer io.Writer } // NewNoOpWriteCloser creates a WriteCloser form a Writer that performs no operation on close. func NewNoOpWriteCloser(writer io.Writer) io.WriteCloser { return &noOpWriteCloser{ writer, } } func (w *noOpWriteCloser) Write(p []byte) (n int, err error) { return w.writer.Write(p) } func (w *noOpWriteCloser) Close() error { return nil } golang-github-protonmail-gopenpgp-v3-3.1.0/internal/sanitize_string.go000066400000000000000000000057221472137411600261620ustar00rootroot00000000000000package internal import ( "bufio" "bytes" "io" "strings" "unicode" "unicode/utf8" ) func SanitizeString(input string) string { return strings.ToValidUTF8(input, string(unicode.ReplacementChar)) } func NewSanitizeReader(r io.Reader) io.Reader { sanitizer := &sanitizeReader{r, new(bytes.Buffer), false} return newSanitizeUtf8Reader(sanitizer) } type sanitizeUtf8Reader struct { r *bufio.Reader reminder []byte internalBuffer [4]byte lastRuneInvalid bool } func newSanitizeUtf8Reader(reader io.Reader) *sanitizeUtf8Reader { return &sanitizeUtf8Reader{ r: bufio.NewReader(reader), } } func (sr *sanitizeUtf8Reader) Read(buf []byte) (int, error) { read := 0 // Check if there is a reminder from the previous read if sr.reminder != nil { toCopy := len(sr.reminder) if toCopy > len(buf) { toCopy = len(buf) } copy(buf[read:], sr.reminder[:toCopy]) read += toCopy if toCopy < len(sr.reminder) { sr.reminder = sr.reminder[toCopy:] } else { sr.reminder = nil } } // Decode utf-8 runes from the internal reader and copy for read < len(buf) { runeItem, size, err := sr.r.ReadRune() if err != nil { return read, err } if runeItem == unicode.ReplacementChar { // If last rune written is a replacement skip if sr.lastRuneInvalid { continue } size = 3 sr.lastRuneInvalid = true } else { sr.lastRuneInvalid = false } if read+size <= len(buf) { utf8.EncodeRune(buf[read:], runeItem) read += size } else { // Not enough space to write the entire rune size = utf8.EncodeRune(sr.internalBuffer[:], runeItem) copied := copy(buf[read:], sr.internalBuffer[:len(buf)-read]) sr.reminder = sr.internalBuffer[copied:size] read += copied break } } return read, nil } type sanitizeReader struct { r io.Reader buffer *bytes.Buffer pin bool } func (sr *sanitizeReader) resetState() { sr.pin = false } func (sr *sanitizeReader) Read(buf []byte) (int, error) { // read from internal buffer first internalRead, _ := sr.buffer.Read(buf) if internalRead == len(buf) { return internalRead, nil } // if there is more space in buf, read from the reader n, err := sr.r.Read(buf[internalRead:]) if err != nil && err != io.EOF { // error occurred that is not EOF return n, err } // filter non-unicode and \r\n in what has been read from the reader, for i := internalRead; i < internalRead+n; { c := buf[i] if sr.pin { // last char read is \r if c == '\n' { sr.buffer.WriteByte('\n') i++ } else { sr.buffer.WriteByte('\r') } sr.resetState() continue } if c == '\r' { // check for \n on next char i++ sr.pin = true continue } sr.resetState() sr.buffer.Write(buf[i : i+1]) i++ } if err == io.EOF && sr.pin { sr.resetState() sr.buffer.WriteByte('\r') } finalRead, _ := sr.buffer.Read(buf[internalRead:]) if err == io.EOF && sr.buffer.Len() == 0 { return internalRead + finalRead, err } return internalRead + finalRead, nil } golang-github-protonmail-gopenpgp-v3-3.1.0/internal/sanitize_string_test.go000066400000000000000000000017031472137411600272140ustar00rootroot00000000000000package internal import ( "bytes" "io" "strings" "testing" "github.com/stretchr/testify/assert" ) func expectedOutput(in string) string { return SanitizeString(strings.ReplaceAll(in, "\r\n", "\n")) } func testStringSanitizeReader(t *testing.T, test string) { reader := NewSanitizeReader(bytes.NewReader([]byte(test))) byteBuffer := new(bytes.Buffer) smallBuff := make([]byte, 3) var err error for err != io.EOF { var n int n, err = reader.Read(smallBuff) byteBuffer.Write(smallBuff[:n]) } assert.Equal(t, byteBuffer.String(), expectedOutput(test)) } func TestStringSanitizeReader(t *testing.T) { test := "a\xc5zsd\xc5\r\ndf\rdf\xc5df\rsdf\r\n\r\n\r\n\r\n\r\n\r\n\r\n" testStringSanitizeReader(t, test) testStringSanitizeReader(t, "\r\n\r\n\r\n\r\n\r\n\r\n\r\n") testStringSanitizeReader(t, "\n") testStringSanitizeReader(t, "\r") testStringSanitizeReader(t, "") testStringSanitizeReader(t, "\xc5\xc5\xc5\xc5\xc5\xc5\xc5\xc5\xc5") } golang-github-protonmail-gopenpgp-v3-3.1.0/internal/testdata/000077500000000000000000000000001472137411600242225ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-v3-3.1.0/internal/testdata/utf8Valid.txt000066400000000000000000000032271472137411600266350ustar00rootroot00000000000000In the realm of encryption, where secrets weave their tale, OpenPGP emerges, a guardian in the digital vale. Keys, like whispers, dance in cryptographic delight, A symphony of security, in the quiet of the 𝓃𝒾𝑔𝒽𝓉. Public and private, a 𝕜𝕖𝕪 𝕡𝕒𝕚𝕣 takes the stage, A ballet of 𝖇𝖎𝖙𝖘, in a secure encryption 𝕔𝕒𝕘𝕖. 𝓐𝓵𝓰𝓸𝓻𝓲𝓽𝓱𝓶𝓼 𝔀𝓪𝓵𝓽𝔃, a choreography so divine, OpenPGP orchestrates, where secrets 𝒾𝓃𝓉𝑒𝓇𝓌𝓲𝓃𝓮. Binary ballet, a dance of ones and zeros, In the realm of cyberspace, where 𝓹𝓻𝓲𝓿𝓪𝓬𝔂 bestows. Messages wrapped in ciphers, like a 𝓹𝓸𝓮𝓽𝓲𝓬 𝓪𝓻𝓽, OpenPGP's embrace, a shield around the 𝓱𝓮𝓪𝓻𝓽. In the 𝓵𝓪𝓷𝓰𝓾𝓪𝓰𝓮 of encryption, trust is finely spun, A shield for emails, where shadows cannot 𝓼𝓱𝓾𝓷. Securely enveloped, like letters sealed with wax, OpenPGP guards the 𝕘𝕒𝕥𝕖𝕤, against unwarranted 𝕒𝕥𝕥𝕒𝕔𝕜𝕤. Through the 𝕧𝕒𝕤𝕥 𝕖𝕩𝕡𝕒𝕟𝕤𝕖 of the digital 𝕤𝕖𝕒, OpenPGP sails, setting secrets 𝓯𝓻𝓮𝓮. A cryptographic journey, in a code-bound 𝕤𝕙𝕚𝕡, Navigating the currents, on a secure 𝕗𝕖𝕝𝕝𝕠𝕨𝕤𝕙𝕚𝕡. So here's to OpenPGP, the 𝓹𝓸𝓮𝓽 of encryption's 𝓵𝓸𝓻𝓮, A guardian of 𝓹𝓻𝓲𝓿𝓪𝓬𝔂, on the digital 𝕤𝕙𝕠𝕣𝕖. In the language of 𝕒𝕝𝕘𝕠𝕣𝕚𝕥𝕙𝕞𝕤, where trust is 𝕕𝕖𝕖𝕡𝕝𝕪 𝕤𝕠𝕨𝕟, OpenPGP, a 𝓹𝓸𝓮𝓶 in 𝖈𝖔𝖉𝖊, forever shall be known.golang-github-protonmail-gopenpgp-v3-3.1.0/internal/utf8.go000066400000000000000000000110711472137411600236260ustar00rootroot00000000000000package internal import ( "errors" "io" "unicode/utf8" ) var ErrIncorrectUtf8 = errors.New("openpgp: data encoding is not valid utf-8") const ( maxRuneSize = 4 locb = 0b10000000 hicb = 0b10111111 xx = 0xF1 as = 0xF0 s1 = 0x02 s2 = 0x13 s3 = 0x03 s4 = 0x23 s5 = 0x34 s6 = 0x04 s7 = 0x44 ) var first = [256]uint8{ // 1 2 3 4 5 6 7 8 9 A B C D E F as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x00-0x0F as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x10-0x1F as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x20-0x2F as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x30-0x3F as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x40-0x4F as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x50-0x5F as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x60-0x6F as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x70-0x7F // 1 2 3 4 5 6 7 8 9 A B C D E F xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0x80-0x8F xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0x90-0x9F xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xA0-0xAF xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xB0-0xBF xx, xx, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, // 0xC0-0xCF s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, // 0xD0-0xDF s2, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s4, s3, s3, // 0xE0-0xEF s5, s6, s6, s6, s7, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xF0-0xFF } type acceptRange struct { lo uint8 hi uint8 } var acceptRanges = [16]acceptRange{ 0: {locb, hicb}, 1: {0xA0, hicb}, 2: {locb, 0x9F}, 3: {0x90, hicb}, 4: {locb, 0x8F}, } func canOverlap(in []byte) []byte { if len(in) < maxRuneSize { return in } return nil } // valid is a slightly modified utf8.Valid() function copied from the standard library. // If the byte slice is not valid utf8, it additionally returns the remaining data if the // remaining data is smaller than the largest potential rune. func valid(p []byte) (bool, []byte) { p = p[:len(p):len(p)] for len(p) >= 8 { first32 := uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24 second32 := uint32(p[4]) | uint32(p[5])<<8 | uint32(p[6])<<16 | uint32(p[7])<<24 if (first32|second32)&0x80808080 != 0 { break } p = p[8:] } n := len(p) for i := 0; i < n; { pi := p[i] if pi < utf8.RuneSelf { i++ continue } x := first[pi] if x == xx { return false, canOverlap(p[i:]) } size := int(x & 7) if i+size > n { return false, canOverlap(p[i:]) } accept := acceptRanges[x>>4] if c := p[i+1]; c < accept.lo || accept.hi < c { return false, canOverlap(p[i:]) } else if size == 2 { } else if c := p[i+2]; c < locb || hicb < c { return false, canOverlap(p[i:]) } else if size == 3 { } else if c := p[i+3]; c < locb || hicb < c { return false, canOverlap(p[i:]) } i += size } return true, nil } type utf8Checker struct { buffer [maxRuneSize]byte overflowSize int } func (c *utf8Checker) check(p []byte) error { pInspect := p if c.overflowSize > 0 { // There is data in the overflow buffer from the last check call copied := copy(c.buffer[c.overflowSize:], p) c.overflowSize += copied r, runeSize := utf8.DecodeRune(c.buffer[:c.overflowSize]) if r == utf8.RuneError && runeSize == 1 { if c.overflowSize < maxRuneSize { // Could still be valid utf-8 on next check return nil } return ErrIncorrectUtf8 } pInspect = pInspect[copied-(c.overflowSize-runeSize):] c.overflowSize = 0 } if len(pInspect) < 1 { return nil } isValid, rest := valid(pInspect) if !isValid && len(rest) > 0 { // Could still be valid utf-8 on next check copy(c.buffer[:], rest) c.overflowSize = len(rest) } else if !isValid { return ErrIncorrectUtf8 } return nil } func (c *utf8Checker) close() error { if c.overflowSize > 0 { return ErrIncorrectUtf8 } return nil } type Utf8CheckWriteCloser struct { utf8Checker internal io.WriteCloser } func NewUtf8CheckWriteCloser(wrap io.WriteCloser) *Utf8CheckWriteCloser { return &Utf8CheckWriteCloser{ internal: wrap, } } func (cw *Utf8CheckWriteCloser) Write(p []byte) (n int, err error) { err = cw.check(p) if err != nil { return } n, err = cw.internal.Write(p) return } func (cw *Utf8CheckWriteCloser) Close() (err error) { err = cw.close() if err != nil { return } err = cw.internal.Close() return } golang-github-protonmail-gopenpgp-v3-3.1.0/internal/utf8_test.go000066400000000000000000000032151472137411600246660ustar00rootroot00000000000000package internal import ( "bytes" "encoding/hex" "errors" "io" "os" "strings" "testing" ) var invalidUtf8 = []string{"f0288cbc", "fc80808080af"} var validUtf8 = []string{"Hell⌘o☏", "World", "||||", "你好,世界!"} type noOpCloser struct { buff *bytes.Buffer } func (c *noOpCloser) Write(p []byte) (n int, err error) { return c.buff.Write(p) } func (c *noOpCloser) Close() (err error) { return } func loadLargeData(t *testing.T) { data, err := os.ReadFile("testdata/utf8Valid.txt") if err != nil { t.Fatal(err) } validUtf8 = append(validUtf8, string(data)) } func TestUtf8CheckWriteCloser(t *testing.T) { loadLargeData(t) t.Run("invalid utf-8", func(t *testing.T) { for _, invalid := range invalidUtf8 { buff := bytes.NewBuffer(nil) writeCloser := NewUtf8CheckWriteCloser(&noOpCloser{buff}) data, _ := hex.DecodeString(invalid) var err error for id := range data { if _, err = writeCloser.Write(data[id : id+1]); err != nil { break } } errClose := writeCloser.Close() if err == nil && errClose == nil { t.Error("Should be invalid utf8") } } }) t.Run("valid utf-8", func(t *testing.T) { for _, copySize := range []int64{1, 3, 7, 11} { for _, valid := range validUtf8 { buff := bytes.NewBuffer(nil) writeCloser := NewUtf8CheckWriteCloser(&noOpCloser{buff}) dataReader := strings.NewReader(valid) for { _, err := io.CopyN(writeCloser, dataReader, copySize) if errors.Is(err, io.EOF) { break } if err != nil { t.Fatal(err) } } if err := writeCloser.Close(); err != nil { t.Error("Should be valid utf8") } } } }) } golang-github-protonmail-gopenpgp-v3-3.1.0/mime/000077500000000000000000000000001472137411600215245ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-v3-3.1.0/mime/mime.go000066400000000000000000000075751472137411600230200ustar00rootroot00000000000000// Package mime provides an API to decrypt mime messages. package mime import ( "bytes" "io" "net/mail" "net/textproto" gomime "github.com/ProtonMail/go-mime" "github.com/ProtonMail/gopenpgp/v3/constants" "github.com/ProtonMail/gopenpgp/v3/crypto" "github.com/ProtonMail/gopenpgp/v3/internal" "github.com/pkg/errors" ) // MIMECallbacks defines callback methods to process a MIME message. type MIMECallbacks interface { OnBody(body string, mimetype string) OnAttachment(headers string, data []byte) // Encrypted headers can be in an attachment and thus be placed at the end of the mime structure. OnEncryptedHeaders(headers string) OnVerified(verified int) OnError(err error) } // Decrypt decrypts and verifies a MIME message. // messageEncoding provides the encoding of the encrypted MIME message, either crypto.Bytes or crypto.Armor. // The decryptionHandle is used to decrypt and verify the message, while // the verifyHandle is used to verify the signature contained in the decrypted mime message. // The verifyHandle can be nil. func Decrypt( message []byte, messageEncoding int8, // crypto.Bytes or crypto.Armor decryptionHandle crypto.PGPDecryption, verifyHandle crypto.PGPVerify, callbacks MIMECallbacks, ) { decResult, err := decryptionHandle.Decrypt(message, messageEncoding) if err != nil { callbacks.OnError(err) return } decryptedMessage := decResult.Bytes() embeddedSigError, _ := separateSigError(decResult.SignatureError()) body, attachments, attachmentHeaders, err := parseMIME(decryptedMessage, verifyHandle) mimeSigError, err := separateSigError(err) if err != nil { callbacks.OnError(err) return } // We only consider the signature to be failed if both embedded and mime verification failed if embeddedSigError != nil && mimeSigError != nil { callbacks.OnError(embeddedSigError) callbacks.OnError(mimeSigError) callbacks.OnVerified(prioritizeSignatureErrors(embeddedSigError, mimeSigError)) } else if verifyHandle != nil { callbacks.OnVerified(constants.SIGNATURE_OK) } bodyContent, bodyMimeType := body.GetBody() bodyContentSanitized := internal.SanitizeString(bodyContent) callbacks.OnBody(bodyContentSanitized, bodyMimeType) for i := 0; i < len(attachments); i++ { callbacks.OnAttachment(attachmentHeaders[i], []byte(attachments[i])) } callbacks.OnEncryptedHeaders("") } // ----- INTERNAL FUNCTIONS ----- func prioritizeSignatureErrors(signatureErrs ...*crypto.SignatureVerificationError) (maxError int) { // select error with the highest value, if any // FAILED > NO VERIFIER > NOT SIGNED > SIGNATURE OK maxError = constants.SIGNATURE_OK for _, err := range signatureErrs { if err.Status > maxError { maxError = err.Status } } return } func separateSigError(err error) (*crypto.SignatureVerificationError, error) { sigErr := &crypto.SignatureVerificationError{} if errors.As(err, sigErr) { return sigErr, nil } return nil, err } func parseMIME( mimeBody []byte, verifyHandle crypto.PGPVerify, ) (*gomime.BodyCollector, []string, []string, error) { mm, err := mail.ReadMessage(bytes.NewReader(mimeBody)) if err != nil { return nil, nil, nil, errors.Wrap(err, "mime: error in reading message") } h := textproto.MIMEHeader(mm.Header) mmBodyData, err := io.ReadAll(mm.Body) if err != nil { return nil, nil, nil, errors.Wrap(err, "mime: error in reading message body data") } printAccepter := gomime.NewMIMEPrinter() bodyCollector := gomime.NewBodyCollector(printAccepter) attachmentsCollector := gomime.NewAttachmentsCollector(bodyCollector) mimeVisitor := gomime.NewMimeVisitor(attachmentsCollector) signatureCollector := newSignatureCollector(mimeVisitor, verifyHandle) err = gomime.VisitAll(bytes.NewReader(mmBodyData), h, signatureCollector) if err == nil && verifyHandle != nil { err = signatureCollector.verified } return bodyCollector, attachmentsCollector.GetAttachments(), attachmentsCollector.GetAttHeaders(), err } golang-github-protonmail-gopenpgp-v3-3.1.0/mime/mime_test.go000066400000000000000000000236721472137411600240530ustar00rootroot00000000000000package mime import ( "errors" "os" "path/filepath" "strings" "testing" "github.com/ProtonMail/gopenpgp/v3/crypto" "github.com/stretchr/testify/assert" ) // Corresponding key in testdata/mime_privateKey. var MIMEKeyPassword = []byte("test") type Callbacks struct { Testing *testing.T } func (t *Callbacks) OnBody(body string, mimetype string) { assert.Exactly(t.Testing, readTestFile("mime_decryptedBody", false), body) } func (t Callbacks) OnAttachment(headers string, data []byte) { assert.Exactly(t.Testing, 1, data) } func (t Callbacks) OnEncryptedHeaders(headers string) { assert.Exactly(t.Testing, "", headers) } func (t Callbacks) OnVerified(verified int) { } func (t Callbacks) OnError(err error) { t.Testing.Fatal("Error in decrypting MIME message: ", err) } func TestDecrypt(t *testing.T) { callbacks := Callbacks{ Testing: t, } privateKey, err := crypto.NewKeyFromArmored(readTestFile("mime_privateKey", false)) if err != nil { t.Fatal("Cannot unarmor private key:", err) } privateKey, err = privateKey.Unlock(MIMEKeyPassword) if err != nil { t.Fatal("Cannot unlock private key:", err) } privateKeyRing, err := crypto.NewKeyRing(privateKey) if err != nil { t.Fatal("Cannot create private keyring:", err) } message := readTestFileBytes("mime_pgpMessage") pgp := crypto.PGP() decHandle, _ := pgp.Decryption().DecryptionKeys(privateKeyRing).New() Decrypt(message, crypto.Armor, decHandle, nil, &callbacks) } type testMIMECallbacks struct { onBody []struct{ body, mimetype string } onAttachment []struct { headers string data []byte } onEncryptedHeaders []string onVerified []int onError []error } func (tc *testMIMECallbacks) OnBody(body string, mimetype string) { tc.onBody = append(tc.onBody, struct { body string mimetype string }{body, mimetype}) } func (tc *testMIMECallbacks) OnAttachment(headers string, data []byte) { tc.onAttachment = append(tc.onAttachment, struct { headers string data []byte }{headers, data}) } func (tc *testMIMECallbacks) OnEncryptedHeaders(headers string) { tc.onEncryptedHeaders = append(tc.onEncryptedHeaders, headers) } func (tc *testMIMECallbacks) OnVerified(status int) { tc.onVerified = append(tc.onVerified, status) } func (tc *testMIMECallbacks) OnError(err error) { tc.onError = append(tc.onError, err) } func loadPrivateKeyRing(file string, passphrase string) (*crypto.KeyRing, error) { armored, err := os.ReadFile(filepath.Clean(file)) if err != nil { return nil, err } unlockedKey, err := crypto.NewPrivateKeyFromArmored(string(armored), []byte(passphrase)) if err != nil { return nil, err } keyRing, err := crypto.NewKeyRing(unlockedKey) if err != nil { return nil, err } return keyRing, nil } func loadPublicKeyRing(file string) (*crypto.KeyRing, error) { armored, err := os.ReadFile(filepath.Clean(file)) if err != nil { return nil, err } key, err := crypto.NewKeyFromArmored(string(armored)) if err != nil { return nil, err } if key.IsPrivate() { publicKey, err := key.GetPublicKey() if err != nil { return nil, err } key, err = crypto.NewKey(publicKey) if err != nil { return nil, err } } keyRing, err := crypto.NewKeyRing(key) if err != nil { return nil, err } return keyRing, nil } func loadMessage(file string) ([]byte, error) { armored, err := os.ReadFile(filepath.Clean(file)) if err != nil { return nil, err } return armored, nil } func runScenario(t *testing.T, messageFile string) *testMIMECallbacks { decryptionKeyRing, err := loadPrivateKeyRing("testdata/mime/decryption-key.asc", "test_passphrase") if err != nil { t.Errorf("Failed to load decryption key %v", err) } verificationKeyRing, err := loadPublicKeyRing("testdata/mime/verification-key.asc") if err != nil { t.Errorf("Failed to load verification key %v", err) } message, err := loadMessage(messageFile) if err != nil { t.Errorf("Failed to load message %v", err) } callbacks := &testMIMECallbacks{} pgp := crypto.PGP() decHandle, _ := pgp.Decryption(). DecryptionKeys(decryptionKeyRing). VerificationKeys(verificationKeyRing). VerifyTime(1557754627). New() verifyHandle, _ := pgp.Verify(). VerificationKeys(verificationKeyRing). VerifyTime(1557754627). New() Decrypt(message, crypto.Armor, decHandle, verifyHandle, callbacks) return callbacks } func compareStatus(expected []int, actual []int, t *testing.T) { if len(actual) != len(expected) { t.Errorf("Expected %v, got %v", expected, actual) } else { for i, actualStatus := range actual { if actualStatus != expected[i] { t.Errorf("Expected status %v, got %v", expected[i], actualStatus) } } } } func TestMessageVerificationOkOk(t *testing.T) { callbackResults := runScenario(t, "testdata/mime/scenario_00.asc") if len(callbackResults.onError) != 0 { for _, err := range callbackResults.onError { t.Errorf("Expected no errors got %v", err) } } expectedStatus := []int{0} compareStatus(expectedStatus, callbackResults.onVerified, t) } func TestMessageVerificationOkNotSigned(t *testing.T) { callbackResults := runScenario(t, "testdata/mime/scenario_01.asc") if len(callbackResults.onError) != 0 { for _, err := range callbackResults.onError { t.Errorf("Expected no errors got %v", err) } } expectedStatus := []int{0} compareStatus(expectedStatus, callbackResults.onVerified, t) } func TestMessageVerificationOkNoVerifier(t *testing.T) { callbackResults := runScenario(t, "testdata/mime/scenario_02.asc") if len(callbackResults.onError) != 0 { for _, err := range callbackResults.onError { t.Errorf("Expected no errors got %v", err) } } expectedStatus := []int{0} compareStatus(expectedStatus, callbackResults.onVerified, t) } func TestMessageVerificationOkFailed(t *testing.T) { callbackResults := runScenario(t, "testdata/mime/scenario_03.asc") if len(callbackResults.onError) != 0 { for _, err := range callbackResults.onError { t.Errorf("Expected no errors got %v", err) } } expectedStatus := []int{0} compareStatus(expectedStatus, callbackResults.onVerified, t) } func TestMessageVerificationNotSignedOk(t *testing.T) { callbackResults := runScenario(t, "testdata/mime/scenario_10.asc") if len(callbackResults.onError) != 0 { for _, err := range callbackResults.onError { t.Errorf("Expected no errors got %v", err) } } expectedStatus := []int{0} compareStatus(expectedStatus, callbackResults.onVerified, t) } func checkIsSigErr(t *testing.T, err error) int { sigErr := &crypto.SignatureVerificationError{} if errors.As(err, &sigErr) { return sigErr.Status } t.Errorf("Expected a signature verification error, got %v", err) return -1 } func compareErrors(expected []crypto.SignatureVerificationError, actual []error, t *testing.T) { if len(actual) != len(expected) { t.Errorf("Expected %v, got %v", expected, actual) } else { for i, err := range actual { actualStatus := checkIsSigErr(t, err) if actualStatus != expected[i].Status { t.Errorf("Expected sig error with status %v, got %v", expected[i].Status, actualStatus) } } } } func TestMessageVerificationNotSignedNotSigned(t *testing.T) { callbackResults := runScenario(t, "testdata/mime/scenario_11.asc") var expectedErrors = []crypto.SignatureVerificationError{newSignatureNotSigned(), newSignatureNotSigned()} compareErrors(expectedErrors, callbackResults.onError, t) expectedStatus := []int{1} compareStatus(expectedStatus, callbackResults.onVerified, t) } func TestMessageVerificationNotSignedNoVerifier(t *testing.T) { callbackResults := runScenario(t, "testdata/mime/scenario_12.asc") var expectedErrors = []crypto.SignatureVerificationError{newSignatureNotSigned(), newSignatureNoVerifier()} compareErrors(expectedErrors, callbackResults.onError, t) expectedStatus := []int{2} compareStatus(expectedStatus, callbackResults.onVerified, t) } func TestMessageVerificationNotSignedFailed(t *testing.T) { callbackResults := runScenario(t, "testdata/mime/scenario_13.asc") var expectedErrors = []crypto.SignatureVerificationError{newSignatureNotSigned(), newSignatureFailed(nil)} compareErrors(expectedErrors, callbackResults.onError, t) expectedStatus := []int{3} compareStatus(expectedStatus, callbackResults.onVerified, t) } func TestMessageVerificationNoVerifierOk(t *testing.T) { callbackResults := runScenario(t, "testdata/mime/scenario_20.asc") var expectedErrors = []crypto.SignatureVerificationError{} compareErrors(expectedErrors, callbackResults.onError, t) expectedStatus := []int{0} compareStatus(expectedStatus, callbackResults.onVerified, t) } func TestMessageVerificationNoVerifierNotSigned(t *testing.T) { callbackResults := runScenario(t, "testdata/mime/scenario_21.asc") var expectedErrors = []crypto.SignatureVerificationError{newSignatureNoVerifier(), newSignatureNotSigned()} compareErrors(expectedErrors, callbackResults.onError, t) expectedStatus := []int{2} compareStatus(expectedStatus, callbackResults.onVerified, t) } func TestMessageVerificationNoVerifierNoVerifier(t *testing.T) { callbackResults := runScenario(t, "testdata/mime/scenario_22.asc") var expectedErrors = []crypto.SignatureVerificationError{newSignatureNoVerifier(), newSignatureNoVerifier()} compareErrors(expectedErrors, callbackResults.onError, t) expectedStatus := []int{2} compareStatus(expectedStatus, callbackResults.onVerified, t) } func TestMessageVerificationNoVerifierFailed(t *testing.T) { callbackResults := runScenario(t, "testdata/mime/scenario_23.asc") var expectedErrors = []crypto.SignatureVerificationError{newSignatureNoVerifier(), newSignatureFailed(nil)} compareErrors(expectedErrors, callbackResults.onError, t) expectedStatus := []int{3} compareStatus(expectedStatus, callbackResults.onVerified, t) } func readTestFile(name string, trimNewlines bool) string { data := string(readTestFileBytes(name)) if trimNewlines { return strings.TrimRight(data, "\n") } return data } func readTestFileBytes(name string) []byte { data, err := os.ReadFile(filepath.Join("testdata/", name)) //nolint:gosec if err != nil { panic(err) } return data } golang-github-protonmail-gopenpgp-v3-3.1.0/mime/signature_collector.go000066400000000000000000000101071472137411600261210ustar00rootroot00000000000000package mime import ( "bytes" "io" "mime" "net/textproto" pgpErrors "github.com/ProtonMail/go-crypto/openpgp/errors" "github.com/ProtonMail/gopenpgp/v3/constants" "github.com/ProtonMail/gopenpgp/v3/crypto" "github.com/ProtonMail/gopenpgp/v3/internal" gomime "github.com/ProtonMail/go-mime" "github.com/pkg/errors" ) // signatureCollector structure. type signatureCollector struct { verifyHandle crypto.PGPVerify target gomime.VisitAcceptor signature string verified error } func newSignatureCollector( targetAcceptor gomime.VisitAcceptor, handle crypto.PGPVerify, ) *signatureCollector { return &signatureCollector{ target: targetAcceptor, verifyHandle: handle, } } // Accept collects the signature. func (sc *signatureCollector) Accept( part io.Reader, header textproto.MIMEHeader, hasPlainSibling, isFirst, isLast bool, ) (err error) { parentMediaType, params, _ := mime.ParseMediaType(header.Get("Content-Type")) if parentMediaType != "multipart/signed" { sc.verified = newSignatureNotSigned() return sc.target.Accept(part, header, hasPlainSibling, isFirst, isLast) } newPart, rawBody := gomime.GetRawMimePart(part, "--"+params["boundary"]) multiparts, multipartHeaders, err := gomime.GetMultipartParts(newPart, params) if err != nil { return err } hasPlainChild := false for _, header := range multipartHeaders { mediaType, _, _ := mime.ParseMediaType(header.Get("Content-Type")) hasPlainChild = (mediaType == "text/plain") } if len(multiparts) != 2 { sc.verified = newSignatureNotSigned() // Invalid multipart/signed format just pass along if _, err = io.ReadAll(rawBody); err != nil { return errors.Wrap(err, "mime: error in reading raw message body") } for i, p := range multiparts { if err = sc.target.Accept(p, multipartHeaders[i], hasPlainChild, true, true); err != nil { return err } } return nil } // actual multipart/signed format err = sc.target.Accept(multiparts[0], multipartHeaders[0], hasPlainChild, true, true) if err != nil { return errors.Wrap(err, "mime: error in parsing body") } partData, err := io.ReadAll(multiparts[1]) if err != nil { return errors.Wrap(err, "mime: error in ready part data") } decodedPart := gomime.DecodeContentEncoding( bytes.NewReader(partData), multipartHeaders[1].Get("Content-Transfer-Encoding")) buffer, err := io.ReadAll(decodedPart) if err != nil { return errors.Wrap(err, "mime: error in reading decoded data") } mediaType, _, _ := mime.ParseMediaType(header.Get("Content-Type")) buffer, err = gomime.DecodeCharset(buffer, mediaType, params) if err != nil { return errors.Wrap(err, "mime: error in decoding charset") } sc.signature = string(buffer) str, _ := io.ReadAll(rawBody) canonicalizedBody := internal.CanonicalizeBytes(internal.TrimEachLineBytes(str)) if sc.verifyHandle != nil { verifyResult, err := sc.verifyHandle.VerifyDetached(canonicalizedBody, buffer, crypto.Armor) if errors.Is(err, pgpErrors.ErrUnknownIssuer) { return newSignatureNoVerifier() } if err != nil { return errors.Wrap(err, "mime: signature verification failed") } sc.verified = verifyResult.SignatureError() } else { sc.verified = newSignatureNoVerifier() } return nil } // GetSignature collected by Accept. func (sc signatureCollector) GetSignature() string { return sc.signature } // newSignatureNotSigned creates a new SignatureVerificationError, type // SignatureNotSigned. func newSignatureNotSigned() crypto.SignatureVerificationError { return crypto.SignatureVerificationError{ Status: constants.SIGNATURE_NOT_SIGNED, Message: "Missing signature", } } // newSignatureNoVerifier creates a new SignatureVerificationError, type // SignatureNoVerifier. func newSignatureNoVerifier() crypto.SignatureVerificationError { return crypto.SignatureVerificationError{ Status: constants.SIGNATURE_NO_VERIFIER, Message: "No matching signature", } } func newSignatureFailed(cause error) crypto.SignatureVerificationError { return crypto.SignatureVerificationError{ Status: constants.SIGNATURE_FAILED, Message: "Invalid signature", Cause: cause, } } golang-github-protonmail-gopenpgp-v3-3.1.0/mime/testdata/000077500000000000000000000000001472137411600233355ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-v3-3.1.0/mime/testdata/mime/000077500000000000000000000000001472137411600242645ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-v3-3.1.0/mime/testdata/mime/decryption-key.asc000066400000000000000000000016371472137411600277310ustar00rootroot00000000000000-----BEGIN PGP PRIVATE KEY BLOCK----- Version: GopenPGP 2.4.5 Comment: https://gopenpgp.org xYYEXNidoBYJKwYBBAHaRw8BAQdA5tcrjOeA3T4EdEYFdatvvc74Om57MWQMkREh sjC5ePv+CQMIya1zJGkQJepgylS8P4mdvG5FckeujdPkVRQGutDYaki4zSyJAk5G fIcNcBH+JUB/rqC+fhW50+FX3maH5lEw/LpQkQOmYOHyESoaoRTQf80pdGVzdEBw cm90b25tYWlsLmNvbSA8dGVzdEBwcm90b25tYWlsLmNvbT7CjAQTFggAPgUCXNid oAmQ0SXZ8I0QC6wWIQSbyyEpkow7QroiEwTRJdnwjRALrAIbAwIeAQIZAQMLCQcC FQgDFgACAiIBAACmIAEAn7pZZEc4DQno5XhnTD3AKPZeRXwJrh8yuX1Y/FDFAAEA /1gmogW3RSePurl9O4ZRKgy28O9nUs1Rj5xfjvD711gEx4sEXNidoBIKKwYBBAGX VQEFAQEHQHdfieoKF+aXdibZJ/jzXBjMh5iqHAhiL9UZhkksO7wNAwEKCf4JAwgJ CvZDu/l2FmC1i4vDtjvjV4LhK5WQ76wupPxICbkm3lNl4GBsVzKQ+iBuwQmK0rrt +EA9u728I1BQ8KiupXg+INqlpiO4lPkv2Z9VU06JwngEGBYIACoFAlzYnaAJkNEl 2fCNEAusFiEEm8shKZKMO0K6IhME0SXZ8I0QC6wCGwwAAPoJAP418zZTD1o/TLfi 06/mVYM0UWMXnrI+92E7nXUqkNWIUgD+J3vbUuYKTm1Ik86zXqOkHpgnyR7yt6kQ RsN2tP8lJQ8= =okmI -----END PGP PRIVATE KEY BLOCK-----golang-github-protonmail-gopenpgp-v3-3.1.0/mime/testdata/mime/scenario_00.asc000066400000000000000000000042431472137411600270610ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: GopenPGP 2.4.5 Comment: https://gopenpgp.org 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 jEoeYMkeq9KD/MHX =6xDM -----END PGP MESSAGE-----golang-github-protonmail-gopenpgp-v3-3.1.0/mime/testdata/mime/scenario_01.asc000066400000000000000000000022131472137411600270550ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: GopenPGP 2.4.5 Comment: https://gopenpgp.org wV4DuoHa5jmSStQSAQdAycIq/h0ma1g8EPMrGpMli8VTdGEg1nqlpuEbJJmo82Qw PChm+Hv2IARa3E2bceP2FQTkuU5M+HzcxjO2Bt9gIRovxqovsykMkaaaMYk0HQCc 0ukBbHiCQ60EMxDtcD8p1RdZmxgB2J9Z0P4prsw7wjRC//AnJxXn6+IqxAG9ZmFL 0EEAso4EOIbK0pIDSuPETa043FeWSM/2a4Y+JlJ3Efg1EmZqDC+YYW3yhiYaTfBB JnQ/c6W0ZoxBnCisUo4oszdg8OXZ5YC0gKE/ITPZGkzPEWvD9s9pgMlBCWWbzB/C bCGyYkxolSVjHadYp0XTp66Naui2AOJMCaIU5WipzRCUtaCyKmcKDFWcmfhsWgMh ED0yCE6uprWflIMijT66pYqE/kqCPJCjchRNJU+V2KhKoud6qBaPe5i+1o7jk4OF BXKMgd0Nz0vo8eX7s7unieM4zGn99WN9g7KQ9jUXDf+MnS9KbCZXjFuDMvLJef4f ZjgpxZudJdIwa2jsg0jwekUUDhbm1jM2q1IHKfYbVOpLmooV5Z4x+rIUqaCNg1bo lGG5LiKck66LQwlUowJIwcoNgu6+gMiodkwKGAMFIrZlwmuzgbwTmAK5n4BtfKdz c6+fZ178oLO7iXFxL8BKnqRcEOU5eyQp8Wz8RfLWKTMQJLkoWEhFGb6zdGT3HPBa iTDDpM/iGQOmk6B7WU0C8l4UvQRdC9XkK5jrLPIzIZui6rcj7Yp6QzxvQuwNfr4g b9JSG/pJhSZMnuF2Gb2sZhaAN8CMtPvpNZn4HGr/+hpd96I4AYmVcCRwQ3oBwnyg ptSnQa9M8lMJ4PpvKGoK+KYV4OvOdpYJbXGwFVlx6YOFtVJ8eEM0+TTLkpv5gKK8 IkAJflUUdL/dG9T8Z3hAesUNut1sfrSJcgTR2jonEB11B11wyj2dsxLj4T70VhtZ SozEc5MCA14E0yfRb4dUBfgiEciGgwnuX2Wd/fC9KeM/o4QSsEaxj1xsTUaqLS7E h1uopO0= =tP1J -----END PGP MESSAGE-----golang-github-protonmail-gopenpgp-v3-3.1.0/mime/testdata/mime/scenario_02.asc000066400000000000000000000042431472137411600270630ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: GopenPGP 2.4.5 Comment: https://gopenpgp.org wV4DuoHa5jmSStQSAQdADluvhsO+2VhNRjIoQCuqXNfB0xnrid79MfpBJ4kMx0Mw QTHDew+u89ol2NcbEhbcCRnGGkETQyzcduDkG0wcDUKg9Hwxz9g/2P0eUxRIkEoh 0uoBGW4doH4VcMljs23bkPTItL69mfFe4wH/OoXctmDYUKschm2nJUOEWiejbYVJ H7tTfGHjm1IGs10gAcHq+9Ea3Aeii8p47/M+3FFIzlfX2X39snX2eFGbKF6xOogG bgtTH+asp5vXQ3MSrn0HhuZVXFH8tAzXrnOJBQqefK2VPA+2FdoZ8N0uzXkl4MxX d33i+6gsDx8ZKEuze03cgAyJC3DAWJm2HzdUSUq3k4f03rhcIoBQi86ZsHChX0t+ Nqg4wnZmqP8cJp7eI09Afa8p/w99cafcw+q9VYFSMjTGVW514e6LwO5sIifW1+rC bCsqyc0RiGZvJ6eXazLPoHCIPnUfguRFbz6N1Ry7HP9Ttzs7jKe37VMcVWGEQ2jW 26v1Sl8Bb0IWw6GgcgMW8Q+5djxln82uiaLqmaOS+YPGIdvKqoX8M/Iz7MQIEQeS DKO0KCETnFloi9AyBtNrR9peZWYmr7XmqsmOfU1lNe1nVxAOEd0+9l8CzExRNcKW sdjrR8DIbi3956qupilCjV1KLth+BLBPjLBtEpfJGpFrQApek3/iJ75f6W/XqALe 2w41+dKDzZF/DIUiTedb6+AYECJdhkcTRURShkjIynaPm9rJiSzE6hIgd5SKT8pZ YBN9H3hc4zkjPThJK8ihSb8ZHjVQuNkCJnKKeLTOfJ5FlBTW6KSVuTfv4mgHMIAl GvyFmKRFkUFLTdrWd2EabHx5wo2ums+q95t7gCI0dFK57v8gWYU8EU6Q9SVlesPg e2ueddP3TkPqRt7PcydtUwJeCNjUn6SuBbXSVVCzkV95vzQ4rChJBO8kLul9QgiD bWTKVFMc1T3EpEyYsMuQqZGy6hC1Kl40ltiJEJv2iyjuhu1PrmeIDrpULFW4S9Ol 2FJaQ4v4r3MMhcoRgveuZ/55BxYrOmnzEuzMUbiBl8j5tXnOiVq9XooDeClVvvLa NbpCiIoyKL+/7wmhAI48exeII/tEbUoc6J1me+58T/1xGz7VU4GGSQgHQ3a56TwZ I6qXlciPbzdbgYpQtGMgLusc/4SNmTifq6vgIKcV4TJWOvscHafxyoYXzNBiJRXc GsZjMdABGYluatj+WORC7kleKwkg5gwfMle8TQPGa+k0WT5fU51sbDe1P4qz60Xf K7ZGwArV5M5A1tMxUXeQ8SgFhFvXPcIybFzBylUO6en7yKOlLroaEOkj9E6N8Y65 9lvsSkXLYDW6GgM2l13ddDp7LdhSBHSeFwcEaAookelpoXUwfXZtKA4mhPumgFCu RF0hHy1ZuAI3pzhSAiGGqiz2bfuAJrtW5px8UPMgGMyNMgy608aeel9/GStLJHET 9R1kh+Ic0VrxYm2YcOuacPv6wOimLm956yJdCSM1sQ33W9XF3Bul5AjxIygvG1VA tCnQLB+5F2S+VqIxZxgsS18lUhl+cngoK5Oe1iQ2dTlJn1/3FYug1oLSFb0q4bq9 f5Q91DP/wHPzF+pEl2eeCz20kTe1FtTDDZc3840/3QyZqvRQINJBPOCEO8sSCzaO b2eDhxE1/LcC5JD5AhYUV9F4HAqA2oshJM+3gjMEspzea47D6IpEdVc/pxq9tl2w MYWky3aHf9PRdGecVlfoomXE86FpyxgFnVF/+XhZUmMCZSKkhLx02rEpc9ar/2zg cG9Uub8TXSiufvAw1IxMHxLOL64Bzv1ywo6XEKZvisI/4YcGjVRbxHhRDrWS0xPH xJotu47brbbasN/Uom8JDMZfjem67Trkj3M0ukNZfBrEoxhQAyEQFHbE6xxOCqgN P4tvOspPBtCLfEy5P+g8Wm0nwohzz91Rt8jcUHAnu6k/c2R0V01Q+jGC/HV3Cgew uuJ5gaOjnbfGj/1vRbCCtL3TowqsThKsLI9TgnIpR9DsU6/l99rZlO07yzmYKkWp BJiF4ywh+5vsIxt9 =i2Op -----END PGP MESSAGE-----golang-github-protonmail-gopenpgp-v3-3.1.0/mime/testdata/mime/scenario_03.asc000066400000000000000000000042431472137411600270640ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: GopenPGP 2.4.5 Comment: https://gopenpgp.org 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 YoUC6jK+JBmHXgE+ =/UZ+ -----END PGP MESSAGE-----golang-github-protonmail-gopenpgp-v3-3.1.0/mime/testdata/mime/scenario_10.asc000066400000000000000000000037601472137411600270650ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: GopenPGP 2.4.5 Comment: https://gopenpgp.org wV4DuoHa5jmSStQSAQdAAqzeTcuIHA/5tKFke+3wRgjInL0EEJBvqE4KHH8vBHYw AeSg3nR9ZTv2W+X1ch5vYbmGWQIjcgc1CiwWGqunAcbK2L9nQXWzvvWXtExqVl1+ 0uoB1EFaOeqRDjDooxaRndogGpt4criBvif+Coz2LWCuwiNF09nIxSfGAre1Z9DU JbWa6o5KUBnR/2yK6XbLc9LkUCnFPimAqHV2c4b7PJVyx6KeJhCQggPWfC3E1hHx lWRkLa3PElaq7TesrPHsZQOsKR4/oliCLv5dvEH4UytXH42zVg9H5vTwT3Gje0EM 3YszSwZKJSEPzgJ6kIhlEvzGurP0gmfNsVt3zlwSlEI5i0RZdIBIk9rC34DFqK5G 19buPOjQCORrQ9+xPcCPaneYwgaiXkWRoedFbwlXMSeDVZbKVBDbSVMXxaqt9fas DF9JfO1VEsZC5jbD1FUTpAnQ5s5gUtaScgFryX6NMQH2UrqTQTprjwdy8u2jTxIa QB+oGU56jCXGIagKWsUXmIqb4IwGs8PiOBgT0ie4Tm/j22+8qZRGTfQ/8J0yXHjM AyfK7vwqrq/LAOVgJKR2dq39Bk5OrwQLDd14GdXN9qWKj0wbG+E+d+5EBO3GsTSW vN5dm7SnoyZkm6JzxOMSpMXl1s2yDpJ9Req8i9q47XhYifYy9QT5brRju7i6NqGD juuQSis8PMQ86RAoniww3zs27LuQxrSA29iS7qlynlZ7ocySTjXU+4gExuEEE2AG KQ6zydWzf73bkZ0MwJ7xeZ6ICenNlmaki8466pKnqOiV92fp6Wx9FKLKMDqULtfX YfJ9wTJZiipJEanW+Nn+pXp7sNbOuSoQ42bnD6kCyv03XGh1cBzIMf7brckUNbVU HXXJGxwTfTzuA4gLdmKy+jgpgBe/NCwqLXDP1KdIOMWFxJQBp6WiXCcpp2bKtUI/ GHIFzjFL16Cp7H8YcXFWuEbeyzLQnq0ahjdTadmmCFuYtv9mKpSyauizzN49SqS3 W4NVi2+ifkRaGklBtdIGMrHvcAjHl1ozW0AEYfOWUSi4udzoiU/usYMo7XGTkY5M E8/hxY/bZmOEkwBHCXQ8wbgcEgIsQqyNU7lH/uUUFVsY5/gFlmioSOuxmapCGLfD JM6UyHYGC7YTiFD2DMIr8UVxUtL/b142EVJDHQES1dmzWfhPZ5RIgIEBd1UJH6sb 9PXWTQt2W8wxy6SfVOTx5KN0+nbMfHpZLG1Rzed/VAlHmNlCfRrWK9lr6c3A8+ld NZhFYSwDz6cm59uyi5ZuUVhDDUAvXtdDwppLlPN8fhUrmAwW9BNN6uIQVgIidTNT bRdR3M/k6B2rTl/GvQpKjVZuTq00RWlTGE47GZG9bq0aT7faj+nSuX55eaRLO7Qd pwHzc/2IoImG83I8nb7W5ByKe/HgF8SpDBW0ZZNqk1h8RMLcUs+adIq+qdyov4kB yX5YVmEOfbVybz/Ojerc4MoowGLuUT/yFvIJp/Vc/oUR8krE6Lbld6pNDiuGfZ0Z QJ3uaeCJjycPSjTuGJ82gX7/RzKKWsYDIuuAv8n7sGTYrIOBn9G5WPPPEAk43a/w 5FZdilJIARp5642TkCJkU/ItfweiYdKnKiGvjjSQ6lo/8Gph9JtfQbNQvdZ4YO7B ZynbwGJsIhCnplVROef6vPF1kwz2NPDuoLDqpvLgnYMuh1jpQuKCvjlgUbK0HJml I0EFCSYF5k+3ngTE0Js3l+DtC/UXt9KmXqPLNqV3covW0RjP4QLjZOyNv1BSplqo LM/VL9cQMhOhkYeTFT7F/jUtoYQFNXKD4MDmYAA4akixJkkXJWqLNoxhPHAyCfoM L5GuAd1FLnyiDYGXuChLmtxmZAzfQA== =qTRr -----END PGP MESSAGE-----golang-github-protonmail-gopenpgp-v3-3.1.0/mime/testdata/mime/scenario_11.asc000066400000000000000000000017241472137411600270640ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: GopenPGP 2.4.5 Comment: https://gopenpgp.org wV4DuoHa5jmSStQSAQdAqOkR+qOMTnX9ti37YPYkqryH+Qz81KzPjMyygVlLDk8w rbHrUqgitGV8b9Q5EFQGDAyEB0cz0mjrCbw9Z03XdwNSX3lR/Jpq06aa4Dvyo509 0ukBbE+Jxqx/uws+klnjTfWkuwWNuZ7jD1RrLfchqgKCMKY+HcZ6tgMq8s8n6wZ5 elBfUH3kC5dSpj2o+ygAXHqaL37OQ9UvK8PQ06qJTcfnddfVuGFqS2kERDgTUDXA hBF/OJV9zk50UP0sPrh+PuQArHmlIPGA5c0gX9ELvSSXTv8ej6f4el19FnRM1Tun TeCbnYcD2sK6TA3838sDb8jP3nz30RvPZql8KEY1J9drRSgZZNUwIaTckb5M1dy+ zE+jxPPMXjTGTDGiwSGOTdp4VSbxknjq4B0YYHjg1c6ZrgTkKzUVFReOR1gzURrg itjmK+TDb47W60AchhUA5jV6AmE8FqEyxudQEXCmfcC+FQxznvXwLN1u3Iq4oFF3 bqQS7BR1vlGv4upTGX8LWdRnA2LuZdBLEoseBhYwKBwFbmSszXgSdPohJ9hDRj0+ Uw2fFYGlYXFPNOkCtT/XxQDuT4MSYJvVyvNw2jPskVCsb9sM+JeNxRduZ6u1RIUp NzedsWRko2ZgarvYuee+fByKHpFXhrIBHSESlAtJMARFzIxpjlekzYXUQHtI6W2x qu/OJ9v2ILNpfbs2isteE2sh3EMspP3Gtzra5NO3CkuUNOCZ5n6NLlBgLEwXkLqM VbigYXrc6zl5XYpByB7LjB8It4HX+CW5tZj3doFJ9TR+0hzIE4udrLHJzpILm4ir dTC9PjjMAO1jXMtaYt6x =4hL/ -----END PGP MESSAGE-----golang-github-protonmail-gopenpgp-v3-3.1.0/mime/testdata/mime/scenario_12.asc000066400000000000000000000037601472137411600270670ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Comment: https://gopenpgp.org Version: GopenPGP 2.4.5 wV4DuoHa5jmSStQSAQdACADZsJjbrw0ad11fbtv6yPjwpgJoXEC/+rSXIrGZZ3Iw 2/5BXG/gNbR51WBpyOcrIrP8aqosBKRhXWSSSSAGPZnbGMcAAaOS7eJU9sofQ20V 0uoBzbA1uOQ/lKCQF64t980VZikBwqyWR/IvQh3EhY0xXzXhkZcQkth7AbbZu/7Y e8WMGHEF/O9Lwwys+HBXJ+zzVJamqnW2ef3CuoEdiY3/+QhQxGyYm9APlIX66pHt iF03QVCqYXPws8xxanW8tYI9uvtQCwDlsHwquoBXexigRQ2Bgsm8mvmp+3top7V6 aVi4W27Tq0sx+3jPLQjF1HK6b/RYFBL4fabSXNmxtNMeOPxYCYRKC4teCYa8MDb+ /HcJeZ8DXBL2EK7emO75YrBSmvhSczpUBx0lva0luGX3UdLUvGuud773DHPll219 tFncoylco/PSgAl+/R2twK34RLQeoDEqBZ046mNVJx8BD/rrS8RBpqfhJKpgZBPj 5CdGstY5L/M7ErSw+nNeBnVPrNXkCvRa/tTcayMT+/9FitoTFcsoan8QZJett1xF 3UbxHJDzCs+zFItPnjqyc8eiAszj1XtzsYpq/SjtGtqDqXwUwszj9dwjJrtDVcRp JUbqHxAjo39fFUQghoOzgFGWY1RnG7PJukbLogPboG/GnjZqfyom2JgdAcuAb8ed 8Yr3dKcwP/NCfXMMiVH15MC1Gq7Tj1H4nQLn10R4H/F26SGzbfAKtaXBsL6WGW51 GbYi3suYDmJ4f5XQIn2j/Vz7YV/OPtVCHXQnPQRqfHI1UQymqzf38g2aGA5sKlTj i7TyMMA2TSoanaSyTVPY1jmYFUsi9OnQZ4+hOzr4RXgTtKQe7lqsOPBBdcmqdoMT 3y6hyXMWkGlXHQ+2y7XEyNIml7T1kXtDtSwYq+rHDZucZCUMChxSxQ32pJq8IMGP NRUXqQQ2I7qUXGUMXNV20LJ3XtuVYdVfaaateeR/lkVYrJyXm0dZkVOLvJiTSE7X ODeGSGqbMCiKR9DY5Cpc4xQ1JqYSkieabDkTmQkN7NsHETGvKfhf368EsFBTg/vK sMEAd5X7d4cnNSs/8+2q4ldM98HSI8ZvLuA1PUfsY/U2CHLy2XvNOlCwakNhQvYy ywfDTV3GMnznkAhD221eXXWh+bn4Owg3/EIzA6iFK9lwgffzdHvRKPppgwCIvK/u xCa7OjbJJISpV+8DXcdhDBEm14tDWsjN5iM7vrDybQcMz8wzQ3diLTNPm0JGlnuk zE0jmpSFkLnHvUyQLDqApnYxP7zI5DfsrTnx0l8/9rNmY+XSs2pAZF59sAmcxyTA 3q0/8Ncf/CixyYQraomKvxl50v0/91lm72aZiEQGNGoKksY/V2NeaeVwf+bPA70w dADBKnqC1kj4R9Zg3GK+N6eeky4as1vivbOltR3XUFKX7g3Yd5XTW3FDvyvpcx6A z7fmCmj8pnVojaXSXa/FBpZowGKQ1dPKl89GsRPb2J3eHyJzykSLRAdreECqHwxv u5mGnfUF5j+7zV4Q9rv4A9kBj3ugKt/+VEyqHXE4HU+/M0zFCTbH6giXixWHWi0E EQxUYnU0mHADEX81FP3ndvTFIubzN46HlZ8/RQ1tdHWmmq6N6CLju8O33esGPS5E 3bvi/LKZr3Um9taVQVaXbfvCNfp8/0gBi3rNWtIRUuq2VyhmQVEt4v+n6+yqWk2N jTC40stDKvQSlOskTUq2ihZ1oRgnL/+NiDCKm3gBD2u0KC2eNMiZMJtM0iVMPin6 vEy9eDvyJivmuYdtxEye6o+bb+v+lbYO8CCrvFtLdS3Dhark49FCLZHDPlGVNJQK 6WhNX56S3HAcqAhRwv35Ovv1+3j0Ug== =nFJS -----END PGP MESSAGE-----golang-github-protonmail-gopenpgp-v3-3.1.0/mime/testdata/mime/scenario_13.asc000066400000000000000000000037601472137411600270700ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: GopenPGP 2.4.5 Comment: https://gopenpgp.org wV4DuoHa5jmSStQSAQdAQEhFBvYT0KFpvjwOSPBIKXhIZRWYHgzcu/+2S3kztg0w bMSNHVoTRHWVD4tAZf2h8EQ4AWIuog5UOvMIezd8nHuwtVDU2ivdf3fyuQA3xQqq 0uoBMA2/LGys0KPIKBYst8BD0Ffo3HguSpYSPrx18d0z7QWuovnvSdIPAPWyc/MS I3CC3GZ6eKBcbPNOCkpbX6/KRvhCIGh/bfHJixyCPTQ1HAzDKz2Xb6gWJBNCVxA+ R0XZQQHxwLlniJSXjYfOatgeo4v5WzYw6gB/DVl7JlKo4OKE9k2B/PHoqctphca1 RYDwqqky2RSF1pdkUiborCKVwxK+8yG28KlZsyCHn/miehYU7SIP9zjHqq6zHkZP /lFxYUJ6jsfNpT5EWBESlebQ5cUWFXKMoV2kRVJDQ99eis0kLC9y5BZ/lBxZIg3w sWPAdmuhTxngT1VqHuHV9NB0urqmop0MoO1ZIEoHeK21UhHNUlV2i/h5/ofRUvbi tg5+DCNUxfxUYMx2w8GmmFRRupZsrebVI3WusrrmQW0K5q4VEr6Har5ZydHzeEvi IrE6SY7DoqYDyrvVd/10lDFeZDGbqI7YayxIF4p2w3hE9bLyBMcVAh6evcti8pHI EPQQBgZEv6qbvsL4rG1ELU8Awjy+Rk9dnJROxOwvYMpZoF8S3E4Y6puqm7QmANVs Q9IdCg++3MgxX7HwR1MuGpcedZ6RKQQAj24VOvlDhy1wTkVDg27e3eCo4Fq9cZQL lyDNoUNomrv8PhllSp4u0a1bxXT9haOUuTRNjNKTxuHF9d3QpmR5MAcpF1q/1bFy Obsr1Ar3EUNv569dHWTXraWFXkkdsXnGQXz7V9UxnAEbkjX0jMKoILRyZkDRsbP9 LKT7ZYddZ3OcorrZuNNqIP7//lMPyQXKCNlpN2oaI9bKYZmjdVt6TZ+xW/nlGZIy ZttUV/c+gZhmulfWSXb3FrFweuhBrXtm7HZ0LDWb6aDhA8zDsozUB2bzDihYm2zC 3e3+p/xikfJcUGWoVzG/3juEV0g879QBQ73asTURvtjiX+vP0mpubmXsCr96JT6I Hid2QKP5m7oml4VRbJ7Jnn00m26cmS16kPgXV5k6NsUPuyXsSUu8d17hYYAi3Z7f r9HhW/6fNRzjMt+MciMwwcxdYmkZY91uiAKCQMVPDqBIBru6TW+tfE5N+yF8zjzS LKoy3K6onR+SL9USivDQoOAjQLGgCtt8HNfz3+df31IW6trcP5wpcfKprkUK1VQx czpHx7onAoect202PVZwjcCtpkRVUj2PF6FB+LPweAKDU02Va2cRIiMO+uHcR46z myG/xZnHi8xv3UgbRSTVWZD1HGZRORVSr4z4OfM6EdUuvv3cUuzhAqfNtO1Xxkqa I2K7krSLCQBs59zhuZ3sbloy+9xK1nrhQLFrTl5LrIn9byW12UvDJutONnkzluIQ H+HmaLWZuJf+sT6QSsCbnc3swGI5B/xelOdHD4tkRhFh0nPA6m/S5pu05j9lqHmE Dl/FCwW+3uQTeGRVk6vW5cdCDWVh03FhkyvUot3608RIy87XqauYI9CCvDRAFpXo xmFtMy5sLkqqvpaOJ5/sz+Q6JSh37vvfIB2OBUMnIM5kBQ/Gk1AJa9rtiEMOmMrF G0BGgb/HvkkPWwz3x5m4zm/3gH2tI0QYk1s3I0zYEzyCeFkUCaPBAsUzE/HFcO+s InfYdeRopEGVahlVOTpcFkxHsJFtx/GRLmU0MlMvf/8pEArCr1kZ3Q+BwY+CBT6T yoJVK4M2ZAggPo9QDwOi/7Ju8Ioe+J6FrOYbYQcat2PZ16skY02DcAC7/tr9UTdt 7Fb/zp+GgKYmKv9dUE0B6EQ2M8BESw== =WmRB -----END PGP MESSAGE-----golang-github-protonmail-gopenpgp-v3-3.1.0/mime/testdata/mime/scenario_20.asc000066400000000000000000000042431472137411600270630ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: GopenPGP 2.4.5 Comment: https://gopenpgp.org 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 nQPktLH4gY71cI8d =0SK5 -----END PGP MESSAGE-----golang-github-protonmail-gopenpgp-v3-3.1.0/mime/testdata/mime/scenario_21.asc000066400000000000000000000022131472137411600270570ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: GopenPGP 2.4.5 Comment: https://gopenpgp.org wV4DuoHa5jmSStQSAQdAWpYKwFZbxRdKxuKFoSDhNlLsvrehzzy60be2k1KQPgkw QFSFTswgBHZ3mV1xIeY0luukv4IzNICFz/R+2NLUUXvDSNP+D6YIgkOhWalBg0jB 0ukB++hJUchQp1bx+3mLHJjfULlkcbU+0IHODnu/LT9TDKvoTXrkVXU77aUIF0Ow ySaXlQB7v14wq2xQG+6Tj9owYK6xIMHYn07HrfyigYUkD6vQbhLkcU0U4lPTsGW8 vDkje7WQMseA099iMG35F9QLJ1k9M0gpqUPlKpqxkD0gjP9wYovi/NPGM8raPu9p e3H2/vqCJIFbzBbCtKL82CNQTrmLMo3ZdlPdXQAJwN6K6aIGCn0g9RoV2pDyGUkK 6NDoU9FGbcVCbO2qOCFaFQxp32mZu4DPxkOpQwCNLRMOgw76zgY9vI4u2SRqANsM L1xPWiofHvNNTa1uFqwp3l3fT76EOZ1kyrP0GhiUjIt72oebZwfzXOYS8sw9abq3 /E0ilit9MVCIlPFOeSTNc1ItU6buMv6gr2fSO/oEDtjvTheZUYuxyedPfvXSwB/2 BUBLnhPtCOI6pnppPVZcDHCrQyByrvgULpHbiF6ZOeAji+v1ZSWhCcgH0IqAV6/y rPFsAMkwiqztjybjqymwHI4+egLZu7lOo2MHzRdNoVgjZ5SfHJ89R0mOS8kqZ1Em LdVsghBMfq/1dazHckmLw1jtEvW+3bg2kULek2S+KM44sPDvfQliPNA2ivqHC8bf 8WxP54CwEukcL7Z/0GYyB+jq5hsULz3+w/bbvBVBeXlIoKJo5ku6SC21FIMp9aqi ydRDXhHIBGYSQTSvgfmpG5sdfFzu5pj+wojlcXId2bsqUb15mud9N+8+Qi7Q0n6y 89WXx415kjU62kvPFJ7bBosfvi8x9y12H9OYtOTydbCWXxJa/j1z3P0wkFuxN3A9 Nz5xDAdrewNO5KxyP1GnZmegDI2x8lfd/6+gL7xfpy98N56mAkwVty1NzR4UbGMQ nOXWs48= =gZHP -----END PGP MESSAGE-----golang-github-protonmail-gopenpgp-v3-3.1.0/mime/testdata/mime/scenario_22.asc000066400000000000000000000042431472137411600270650ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: GopenPGP 2.4.5 Comment: https://gopenpgp.org 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 HOwmXIQbo62hfZVd =d+Do -----END PGP MESSAGE-----golang-github-protonmail-gopenpgp-v3-3.1.0/mime/testdata/mime/scenario_23.asc000066400000000000000000000042431472137411600270660ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: GopenPGP 2.4.5 Comment: https://gopenpgp.org wV4DuoHa5jmSStQSAQdAE+PTO7W4TYPFg94xbE5Dq0E/XxBgLbiIeZRKfJ7PQWUw BP9zce4xIVOtt42SjKSlXZ0rAA7lEQSGkYbKKqzfNbNdpbKTgXVzLcDaKaey9Lpe 0uoBOTgSTIGE1HlRpiLJ4ZH/ex33ZiFy1sCoO0pLQjShDAjOWiEXaQywAFoW8zrS zMKq4CK/49Lr8x3T1kvataahykj65EjSM8U/XimvK0WsgPATxcMoA1vDjIlk5Mlu G9D4W+sRn4uwYxwB92nznx+e/HtOC6qnZCqZJw+ska5fG0gcmzQknpey6REflFMs aY+ULN9Q0KgSzVzRXIuVt2ycKZbMDjQq4SlSi6LEeCfuHvBEG85Gp/IfleYQwPd/ S9mVNyQl2hfK/a91h1uk6qabwccpV+mhqQqVavGHeBlO0xpM9B3aWGYS560WPq2L OeU0X1oRmotaFwn5EOkBLE6Wd1gSrd9nrXGPSLwkAWXm1GWltPQ9WLdqWvTPAkGm zunogsQJGVFGelt8T3uFFTC3gGq1dQhGarqpaEr9XR4A9F61Fg5YGpxWtnAWNWUF OxbFN52CzhP5oUFqtu0hSUI3RfFwNzx3c1AKqxkkJvUOpOjosaSfDpd5V4Yr9M0z t+1tqc5dJAkkHZXIdKk9DfYJGu6JjKGjgEMGiDdfRLYopBVH5ZkMU4KtgkbuPsa8 EcxOktrAc5PQWYk3Tm4JNBIzEtDyncWo9ZpiNsPOsOWOpVfmOtWIXymjYXaf1yh2 f9dVc+YprsCHkcCwIJNDgpMgVijvr45eEmu/DDb3+t0cr+t06uGsmz69Aw1HieCe mnvAKc48uSu9Vt+jQ3eEaGnx6QGm6DTY9IdjIFeF84ANkQuYWPzvrFDjvj7qA4Ir X+NYBLqd+USt82spCrZHcIn+O7nulxGcTgiAL/RwSEeAdjkxCHNQJa174P6HjQXx mBN0wp2MpfAj4yVe80yAfLSUGQUnTP/hq1QaALO0HJbnsI2MuSUEzY4VDmxZCaHH PiFx02VY9RfsWJ7M4CJjGoDZ8mWEWubR50G4t6966yw/pNqPUEtq0Hu6wGuKOtzb J6+TufVgvSFOiTJb11d2dO80HXGNsGISTavek5kI1IlDdQ1rHMllaVUuLlSmAGT1 6qmV+DjUo1b2Nkj6ZoBpS162YwZnksVxwubmxySmebW4SpTByO7q5rUXvUdl4Lpy RXsIqH4uAI10DCEx2YNoigjxJe5WksOAHNqXHIHf96rMUQ8U4a4nfkNYrXJ9741A mqdVp0Jo7igSS12vyGKJ9gDbuWh0SMJv8DmfCjMVNtd1/eduOxWQUn0gGZ5+he8Y yFNNYzFmP4nDldtt8CbJPaAOnQqAwiUnXrQs0LThj/+0Obevj3Ts23EMtiOmANER oJVbWLqvMy+LQYgUiFACj0ExsD7MAyeDvBgzn0gHHF6r6DlFefc2FPvOW8g3q96h AAPemuXQkLOv/ZAf8dJfsCpAwOgsrrgCV0UQGpA2KSQKvrML1lfunrDRLWh01ehe 4HxZIV901vQA8UzPvvLteHgn55upToT+zrQnmk/+JtpRrknWej+ugk0D27p7rhF+ IO2f3jl3jg8dFsdeItT9zGZYb/E4tKsbt9qFvqqYY2uSQIMNUurowHPhvdvkMy9E 3xMUWox+za0bOdPYQZSvELqlePyqwukYqMkuEqCDLuvpWf+57mrXDxcrTH+T2C6q T/P0bss8tgpvZ0fO3Qj4P0X0jv/EorSjyFImRkjl4WodcYs/IfG13KGZVke4ve6F gBT+XjM6Am3CoS9comE0qcqN22KJwXSL3CZt/qEIdyEBh9Ge3SVrwC+Bsyl9hMsF 3myZBB/LYbD8vh+2T8Xl0JvQEhiznGunmO9/uxmqQygY2g3RrVmJze7lOSD+tHNc h6Lw7jfMpsSddT1wmNNmU/XdAcmS5tRS4kHmqeaxqOeWnYl8e+vy89jsXO5M3N6X bi3C+Orst+FBbaP3Q4LJKoDG4O4OJ5+uMtnNC4OKB7KN60ZaIJ0terjTf7K/9gjk fuoVwj3delL/Ndzc =sXg5 -----END PGP MESSAGE-----golang-github-protonmail-gopenpgp-v3-3.1.0/mime/testdata/mime/verification-key.asc000066400000000000000000000012751472137411600302310ustar00rootroot00000000000000-----BEGIN PGP PUBLIC KEY BLOCK----- Version: GopenPGP 2.4.5 Comment: https://gopenpgp.org xjMEXNidoBYJKwYBBAHaRw8BAQdAQMB1pb2SfHhzpycpIy6iDyU7oMXWXgZsKxAz X3lTEq7NKXRlc3RAcHJvdG9ubWFpbC5jb20gPHRlc3RAcHJvdG9ubWFpbC5jb20+ wowEExYIAD4FAlzYnaAJkNLQ/NBUB1IfFiEEauk3gpYXSZa4G3Fw0tD80FQHUh8C GwMCHgECGQEDCwkHAhUIAxYAAgIiAQAA0T8BAOwwjUxGfoaasnsSF2dtkP385bqW ZCYaIl9c2WZuF0TwAQD482U7ymKWAzwwruMh8hl3oDZFG4KPKUdJOEY9UqsKAs44 BFzYnaASCisGAQQBl1UBBQEBB0ArwsHX08RHU5mUlixhavveY4mrZe/4PtHE//Cg oYZwLQMBCgnCeAQYFggAKgUCXNidoAmQ0tD80FQHUh8WIQRq6TeClhdJlrgbcXDS 0PzQVAdSHwIbDAAAf+QA/3c701MpUo8p/P4EKPzhskIJ1vxhojvFBNcHMK2xC8q7 AP9Ghc67vUniu7oMsIiKTJlLIDYLQ0UDmHaifXwk9KD5Aw== =5mEE -----END PGP PUBLIC KEY BLOCK-----golang-github-protonmail-gopenpgp-v3-3.1.0/mime/testdata/mime_decodedBody000066400000000000000000000013331472137411600264740ustar00rootroot00000000000000


Screenshot from 2018-02-06 17-13-21.png
-- 
Julien Palard
https://mdk.fr

golang-github-protonmail-gopenpgp-v3-3.1.0/mime/testdata/mime_decodedBodyHeaders000066400000000000000000000001121472137411600277620ustar00rootroot00000000000000Content-Transfer-Encoding: base64 Content-Type: text/html;charset=utf-8 golang-github-protonmail-gopenpgp-v3-3.1.0/mime/testdata/mime_decryptedBody000066400000000000000000000005411472137411600270700ustar00rootroot00000000000000Pak > On Aug 13, 2018, at 4:15 PM, Telekja wrote: > > Encrypted & Signed PGP part > ssdaadsdasads > > > Sent with ProtonMail Secure Email. > > ‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐ > On August 13, 2018 4:12 PM, PGP Test wrote: > >> Test 123 >> BOBOHRI > > golang-github-protonmail-gopenpgp-v3-3.1.0/mime/testdata/mime_pgpMessage000066400000000000000000000061601472137411600263650ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: ProtonMail Comment: https://protonmail.com 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 LloBMV1YNGsW45M+oQ== =BRHT -----END PGP MESSAGE----- golang-github-protonmail-gopenpgp-v3-3.1.0/mime/testdata/mime_privateKey000066400000000000000000000151711472137411600264170ustar00rootroot00000000000000-----BEGIN PGP PRIVATE KEY BLOCK----- Version: GopenPGP.js v3.1.2 Comment: https://openpgpjs.org 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 =xWqS -----END PGP PRIVATE KEY BLOCK----- golang-github-protonmail-gopenpgp-v3-3.1.0/mime/testdata/mime_publicKey000066400000000000000000000061071472137411600262220ustar00rootroot00000000000000-----BEGIN PGP PUBLIC KEY BLOCK----- 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 OQTmvM6R =DvFv -----END PGP PUBLIC KEY BLOCK----- golang-github-protonmail-gopenpgp-v3-3.1.0/mime/testdata/mime_testMessage000066400000000000000000000153101472137411600265530ustar00rootroot00000000000000Content-Type: multipart/signed; protocol="application/pgp-signature"; micalg=pgp-sha256; boundary="---------------------4a9ea9f4dad3f36079bdb3f1e7b75bd0"; charset=UTF-8 X-Spam-Status: No, score=1.2 required=7.0 tests=ALL_TRUSTED,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM, FREEMAIL_REPLYTO_END_DIGIT,HTML_IMAGE_ONLY_08,HTML_MESSAGE autolearn=no autolearn_force=no version=3.4.0 X-Spam-Level: * X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on mail.protonmail.ch -----------------------4a9ea9f4dad3f36079bdb3f1e7b75bd0 Content-Type: multipart/mixed; boundary="---------------------f0e64db835d0f5c3674df52a164b06bb" -----------------------f0e64db835d0f5c3674df52a164b06bb Content-Type: multipart/alternative; boundary="---------------------3ca028eaeffb3ca0fb0dd6461f639c2b" -----------------------3ca028eaeffb3ca0fb0dd6461f639c2b Content-Transfer-Encoding: quoted-printable Content-Type: text/plain;charset=utf-8 [Screenshot from 2018-02-06 17-13-21.png] --=C2=A0 Julien Palard https://mdk.fr -----------------------3ca028eaeffb3ca0fb0dd6461f639c2b Content-Type: multipart/related; boundary="---------------------ce717c368c2d3981c954ad7c46cd7bf2" -----------------------ce717c368c2d3981c954ad7c46cd7bf2 Content-Type: text/html;charset=utf-8 Content-Transfer-Encoding: base64 PGRpdj48ZGl2Pjxicj48L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2IGNsYXNzPSJwcm90b25tYWls X3NpZ25hdHVyZV9ibG9jayI+PGRpdiBjbGFzcz0icHJvdG9ubWFpbF9zaWduYXR1cmVfYmxvY2st dXNlciI+PGRpdj48aW1nIHNyYz0iY2lkOjQ2MDk4ZTliQHByb3Rvbm1haWwuY29tIiBjbGFzcz0i cHJvdG9uLWVtYmVkZGVkIiBhbHQ9IlNjcmVlbnNob3QgZnJvbSAyMDE4LTAyLTA2IDE3LTEzLTIx LnBuZyI+PGJyPjwvZGl2PjxkaXY+LS0mbmJzcDs8YnI+PC9kaXY+PGRpdj5KdWxpZW4gUGFsYXJk PGJyPjwvZGl2PjxkaXY+PGNvZGUgc3R5bGU9ImZvbnQtZmFtaWx5OidTRk1vbm8tUmVndWxhcics IENvbnNvbGFzLCAnTGliZXJhdGlvbiBNb25vJywgTWVubG8sIENvdXJpZXIsIG1vbm9zcGFjZTtm b250LXNpemU6MTEuODk5OTk5NjE4NTMwMjczcHg7cGFkZGluZzowcHg7bWFyZ2luOjBweDtiYWNr Z3JvdW5kLWNvbG9yOnRyYW5zcGFyZW50O3doaXRlLXNwYWNlOnByZTtib3JkZXI6MHB4O2Rpc3Bs YXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7bGluZS1oZWlnaHQ6aW5oZXJpdDsiPjxhIGhyZWY9 Imh0dHBzOi8vbWRrLmZyIj5odHRwczovL21kay5mcjwvYT48L2NvZGU+PGJyPjwvZGl2PjwvZGl2 PjxkaXYgY2xhc3M9InByb3Rvbm1haWxfc2lnbmF0dXJlX2Jsb2NrLXByb3RvbiBwcm90b25tYWls X3NpZ25hdHVyZV9ibG9jay1lbXB0eSI+PGJyPjwvZGl2PjwvZGl2PjwvZGl2Pg== -----------------------ce717c368c2d3981c954ad7c46cd7bf2-- -----------------------3ca028eaeffb3ca0fb0dd6461f639c2b-- -----------------------f0e64db835d0f5c3674df52a164b06bb Content-Type: image/png; filename="Screenshot from 2018-02-06 17-13-21.png"; name="Screenshot from 2018-02-06 17-13-21.png" Content-Disposition: inline; filename="Screenshot from 2018-02-06 17-13-21.png"; name="Screenshot from 2018-02-06 17-13-21.png" Content-ID: <46098e9b@protonmail.com> wsBcBAEBCAAQBQJbjodcCRDdVS3pfakUGgAAlhoH/2jBRjOSx5EdkiyyNcCT 4DVm+ACoF1KTWE5fLRuDPvSiD934cFoZShJs32r0Wcj/4W4tVhLYzjjtf6xO Ymqe0p3o4oYxxMXIAd4COrnOPGjeD1ausqT6iUCAadqXoDYfowEg4f0Wd0RK ElsP/OZaDjsNoRE3WeRcHTr5XWZxhEsIMgnW591iaTliYvbysLoQ08i3G53c p6q+IANRznx5rDhMdo+shFvhcI2Zszg6X2WuCMhFtUyrqEN8WlZYXMX8PGPO 1kNDRl7B7/r4Ap+FffLpeYw+8rG6lQXGc3RCOAnfMq9X/9Ziqzxr7flYtRJH RIzX2CG47PuGl/uvImFW/Iw= -----------------------f0e64db835d0f5c3674df52a164b06bb Content-Type: application/pgp-keys; filename="publickey - kaykeytest3@protonmail.com - 0xE1DADAE3.asc"; name="publickey - kaykeytest3@protonmail.com - 0xE1DADAE3.asc" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="publickey - kaykeytest3@protonmail.com - 0xE1DADAE3.asc"; name="publickey - kaykeytest3@protonmail.com - 0xE1DADAE3.asc" LS0tLS1CRUdJTiBQR1AgUFVCTElDIEtFWSBCTE9DSy0tLS0tDQpWZXJzaW9uOiBPcGVuUEdQLmpz IHYzLjEuMg0KQ29tbWVudDogaHR0cHM6Ly9vcGVucGdwanMub3JnDQoNCnhzQk5CRnQ2N2I4QkNB QzBTMlU3VUJ3dnkyUnZqcEpwOHlyMlE0R25oNzk0QjUwVG1TMlViTXJRaEovaQpUWFRTZmJhb21l NkdkcmJhSjlvVW0xY2hhMU5hVlNnWHE0RVB2WWxmSWVVdkt1U0tnTVdxaVMzT2xSdGYKT3JwMVZp dXNpZWtldVczL2JtYUZBbzFLQWZvajBMNlF6cVVIY3ZZNnY1RExoWGV2MWlaUW9TN2lrQk9PCmor Z05lUDJabjVIOXdQTFlxdWlqK0pnWFY4djRRQk5uNU82NUNYRkZIbjl1Mzl1Yng2bDJtY2tqaDVm VQppU1FiUkh2RzhIdG96Y2xIcWV1bjBpanNjZEtoOTBsaENsWHlDcHlkZ2JwT2pjL2dDQ2R3WmVh djNNSG0KZnhsd2VReDhmc0xxZ1h5TlNFd3pyODh0MTFWMFQ4TmRjeFdia1lRNllQN2R4UU10RkU0 bWM5akxBQkVCCkFBSE5PU0pyWVhsclpYbDBaWE4wTTBCd2NtOTBiMjV0WVdsc0xtTnZiU0lnUEd0 aGVXdGxlWFJsYzNRegpRSEJ5YjNSdmJtMWhhV3d1WTI5dFBzTEFkUVFRQVFnQUtRVUNXM3J0dndZ TENRY0lBd0lKRU4xVkxlbDkKcVJRYUJCVUlDZ0lERmdJQkFoa0JBaHNEQWg0QkFBQ0dEZ2Y5SHVq aG9QUGN5SHpLd25JbFJJaENRL1dLCm13SVVFdEw4eU03aGRvci9zK0kyL1A3WkJHWE1ReXBKb3JD YTU1NUY2ODRMZnpWdUtBUVFMdXZpNHR6aQo5N2JSNE1ldHY4a2ptSUI1Rk0vNUhpWllWd090SDFK dU5iM2RQWG9CVjJha09ScnFCeVRjbjEyeUIwOVkKd0tZR0Y4K25XNFhLU1F2V3VBWWVIZ0dQKzMz ZTdCc0VvODhuRmJJUXl2cmUzUTN0TkJrWTVVVnA2L1M2ClpLZWJwaEFRQVlzM0ZVVlZVeThlZkhr aEFmZFlSdUFBUUFoWnJGanU0V1J0RGZkUHdLR0UzZDZsUGswSApNSFNTUXNHb2thQTVoTnUycE1S Mnl5UmtUa3JyNnRXbmlET2ZvSmtKcmc2VllHNVRwaHZnOE43dVdzZHQKZkhDdDBwWW9uYTRzclZx a0RzN0FUUVJiZXUyL0FRZ0F6b2tCSGZucnFXUXE4RUVSYUVlOUpmZkQ3V0FpCnZyU29lNDdxQ05l S2I2MmcvLzh0Q1dKMHVlRExTMFRyY0V4cnVzUi8rSFdoYUFTV2srL0lPTGhjRTcrVgp4V2Nab0dp bzNuc1puTktWdnFhendNSW1vMnFqdUllUnVCVkJqRW5OOERhOXlxNkJ3YVkvSEs2czM5Y3IKQVVV d2FtWjVuMDNtSFR6MzBMQllYR1VldVc5c3Z4NDIzbTlXb3N2WlQvUWRKWW1qMG44NmpGNGs2Tnh2 ClV4ejR1bmV1YWt1Wld5NmNURHg1WFdWVWF1YzlyV1Z5Uzk3cjJ0NllpRlF6MTFiOU5oZm4rcDVs UmdZbgpzMzQwT1MyVmppK1BVeUVKZ2YzYi9MQlJ5V3Erbk1Vc2lRV09yYlQxblVCVzNRdDViWWhH MUhnT1o5eEoKVjd2dndSZHFwQ1p2cVFBUkFRQUJ3c0JmQkJnQkNBQVRCUUpiZXUyL0NSRGRWUzNw ZmFrVUdnSWJEQUFBClhrTUgvaTBoTnRwRWIrYUZONC9Ba0JCam1GOFJZV243anRyK2UyU05STHdF RUMxcmdmakhjWXZnanJFTQo2Y3hBcXVzSWJKSEdnSUVYZ0s1YUlNOHBGLzRuamN2VXVxa0x1b1o3 QVJsanpwUTcvaHhyc0FNWnFYR2gKeEU4eXJZVlY0dGhhZWw0Q1NRUTRvRWlpbXB4Z28velE5bzhk NGNQUTM4Ni9VNEgvMm9OczFUMElCOTZWCkJsTy9pM0w5eGM4K2w4RG8vcm5ieVV1Ym9LUVNKZmtp RXNLMkRabEZoOVArdVltQ1AzVGJSb2NIUFZtVwpBT3NHVVhJSXROaVNTc05ORUlHeVBSNE8rMXRq VUJPMFNHRnZoVVZUNnJLYTlaYUVyMzI2ZmU2S0pmZU8KYTl4a21WZEdaQm9SdENmbHhiakdnYjRq dTJ3Z1E1TE5KWUNWZy9WRkxIRGI3MjQ9DQo9YmNvMw0KLS0tLS1FTkQgUEdQIFBVQkxJQyBLRVkg QkxPQ0stLS0tLQ0KDQo= -----------------------f0e64db835d0f5c3674df52a164b06bb-- -----------------------4a9ea9f4dad3f36079bdb3f1e7b75bd0 Content-Type: application/pgp-signature; name="signature.asc" Content-Description: GopenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: ProtonMail Comment: https://protonmail.com wsBcBAEBCAAQBQJbjodcCRDdVS3pfakUGgAAlhoH/2jBRjOSx5EdkiyyNcCT 4DVm+ACoF1KTWE5fLRuDPvSiD934cFoZShJs32r0Wcj/4W4tVhLYzjjtf6xO Ymqe0p3o4oYxxMXIAd4COrnOPGjeD1ausqT6iUCAadqXoDYfowEg4f0Wd0RK ElsP/OZaDjsNoRE3WeRcHTr5XWZxhEsIMgnW591iaTliYvbysLoQ08i3G53c p6q+IANRznx5rDhMdo+shFvhcI2Zszg6X2WuCMhFtUyrqEN8WlZYXMX8PGPO 1kNDRl7B7/r4Ap+FffLpeYw+8rG6lQXGc3RCOAnfMq9X/9Ziqzxr7flYtRJH RIzX2CG47PuGl/uvImFW/Iw= =t7ak -----END PGP SIGNATURE----- -----------------------4a9ea9f4dad3f36079bdb3f1e7b75bd0-- golang-github-protonmail-gopenpgp-v3-3.1.0/mobile/000077500000000000000000000000001472137411600220445ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-v3-3.1.0/mobile/mobile.go000066400000000000000000000004041472137411600236400ustar00rootroot00000000000000// Package mobile provides tools for mobile compatibility. package mobile import "runtime/debug" // FreeOSMemory can be used to explicitly // call the garbage collector and // return the unused memory to the OS. func FreeOSMemory() { debug.FreeOSMemory() } golang-github-protonmail-gopenpgp-v3-3.1.0/mobile/mobile_stream.go000066400000000000000000000175031472137411600252230ustar00rootroot00000000000000package mobile import ( "bytes" "crypto/sha256" "hash" "io" "github.com/ProtonMail/gopenpgp/v3/crypto" "github.com/pkg/errors" ) // Mobile2GoWriter is used to wrap a writer in the mobile app runtime, // to be usable in the golang runtime (via gomobile). type Mobile2GoWriter struct { writer crypto.Writer } // NewMobile2GoWriter wraps a writer to be usable in the golang runtime (via gomobile). func NewMobile2GoWriter(writer crypto.Writer) *Mobile2GoWriter { return &Mobile2GoWriter{writer} } // Write writes the data in the provided buffer in the wrapped writer. // It clones the provided data to prevent errors with garbage collectors. func (w *Mobile2GoWriter) Write(b []byte) (n int, err error) { bufferCopy := clone(b) return w.writer.Write(bufferCopy) } // Mobile2GoWriterWithSHA256 is used to wrap a writer in the mobile app runtime, // to be usable in the golang runtime (via gomobile). // It also computes the SHA256 hash of the data being written on the fly. type Mobile2GoWriterWithSHA256 struct { writer crypto.Writer sha256 hash.Hash } // NewMobile2GoWriterWithSHA256 wraps a writer to be usable in the golang runtime (via gomobile). // The wrapper also computes the SHA256 hash of the data being written on the fly. func NewMobile2GoWriterWithSHA256(writer crypto.Writer) *Mobile2GoWriterWithSHA256 { return &Mobile2GoWriterWithSHA256{writer, sha256.New()} } // Write writes the data in the provided buffer in the wrapped writer. // It clones the provided data to prevent errors with garbage collectors. // It also computes the SHA256 hash of the data being written on the fly. func (w *Mobile2GoWriterWithSHA256) Write(b []byte) (n int, err error) { bufferCopy := clone(b) n, err = w.writer.Write(bufferCopy) if err == nil { hashedTotal := 0 for hashedTotal < n { hashed, err := w.sha256.Write(bufferCopy[hashedTotal:n]) if err != nil { return 0, errors.Wrap(err, "gopenpgp: couldn't hash encrypted data") } hashedTotal += hashed } } return n, err } // GetSHA256 returns the SHA256 hash of the data that's been written so far. func (w *Mobile2GoWriterWithSHA256) GetSHA256() []byte { return w.sha256.Sum(nil) } // MobileReader is the interface that readers in the mobile runtime must use and implement. // This is a workaround to some of the gomobile limitations. type MobileReader interface { Read(max int) (result *MobileReadResult, err error) } // MobileReadResult is what needs to be returned by MobileReader.Read. // The read data is passed as a return value rather than passed as an argument to the reader. // This avoids problems introduced by gomobile that prevent the use of native golang readers. type MobileReadResult struct { N int // N, The number of bytes read IsEOF bool // IsEOF, If true, then the reader has reached the end of the data to read. Data []byte // Data, the data that has been read } // NewMobileReadResult initialize a MobileReadResult with the correct values. // It clones the data to avoid the garbage collector freeing the data too early. func NewMobileReadResult(n int, eof bool, data []byte) *MobileReadResult { return &MobileReadResult{N: n, IsEOF: eof, Data: clone(data)} } func clone(src []byte) (dst []byte) { dst = make([]byte, len(src)) copy(dst, src) return } // Mobile2GoReader is used to wrap a MobileReader in the mobile app runtime, // to be usable in the golang runtime (via gomobile) as a native Reader. type Mobile2GoReader struct { reader MobileReader } // NewMobile2GoReader wraps a MobileReader to be usable in the golang runtime (via gomobile). func NewMobile2GoReader(reader MobileReader) *Mobile2GoReader { return &Mobile2GoReader{reader} } // Read reads data from the wrapped MobileReader and copies the read data in the provided buffer. // It also handles the conversion of EOF to an error. func (r *Mobile2GoReader) Read(b []byte) (n int, err error) { result, err := r.reader.Read(len(b)) if err != nil { return 0, errors.Wrap(err, "gopenpgp: couldn't read from mobile reader") } n = result.N if n > 0 { copy(b, result.Data[:n]) } if result.IsEOF { err = io.EOF } return n, err } // Go2AndroidReader is used to wrap a native golang Reader in the golang runtime, // to be usable in the android app runtime (via gomobile). type Go2AndroidReader struct { isEOF bool reader crypto.Reader } // NewGo2AndroidReader wraps a native golang Reader to be usable in the mobile app runtime (via gomobile). // It doesn't follow the standard golang Reader behavior, and returns n = -1 on EOF. func NewGo2AndroidReader(reader crypto.Reader) *Go2AndroidReader { return &Go2AndroidReader{isEOF: false, reader: reader} } // Read reads bytes into the provided buffer and returns the number of bytes read // It doesn't follow the standard golang Reader behavior, and returns n = -1 on EOF. func (r *Go2AndroidReader) Read(b []byte) (n int, err error) { if r.isEOF { return -1, nil } n, err = r.reader.Read(b) if errors.Is(err, io.EOF) { if n == 0 { return -1, nil } else { r.isEOF = true return n, nil } } return } // Go2IOSReader is used to wrap a native golang Reader in the golang runtime, // to be usable in the iOS app runtime (via gomobile) as a MobileReader. type Go2IOSReader struct { reader crypto.Reader } // NewGo2IOSReader wraps a native golang Reader to be usable in the ios app runtime (via gomobile). func NewGo2IOSReader(reader crypto.Reader) *Go2IOSReader { return &Go2IOSReader{reader} } // Read reads at most bytes from the wrapped Reader and returns the read data as a MobileReadResult. func (r *Go2IOSReader) Read(max int) (result *MobileReadResult, err error) { b := make([]byte, max) n, err := r.reader.Read(b) result = &MobileReadResult{} if err != nil { if errors.Is(err, io.EOF) { result.IsEOF = true } else { return nil, err } } result.N = n if n > 0 { result.Data = b[:n] } return result, nil } // KeyPacketSplitWriter implements the crypto.PGPSplitWriter interface // for splitting encryptions output into different packets. // Internally buffers the key packets and potential detached encrypted signatures. type KeyPacketSplitWriter struct { dataWriter crypto.Writer keyPacket *bytes.Buffer encDetachedSignature *bytes.Buffer } func NewKeyPacketSplitWriter(dataWriter crypto.Writer) *KeyPacketSplitWriter { return &KeyPacketSplitWriter{ dataWriter: dataWriter, keyPacket: bytes.NewBuffer(nil), } } // KeyPackets returns the internally buffered key packets. func (sw *KeyPacketSplitWriter) KeyPackets() []byte { return sw.keyPacket.Bytes() } // EncryptedDetachedSignature returns the internally buffered encrypted detached signature. func (sw *KeyPacketSplitWriter) EncryptedDetachedSignature() *crypto.PGPMessage { return crypto.NewPGPSplitMessage(sw.keyPacket.Bytes(), sw.encDetachedSignature.Bytes()) } // Implement the crypto.PGPSplitWriter interface. func (sw *KeyPacketSplitWriter) Write(b []byte) (n int, err error) { return sw.dataWriter.Write(b) } func (sw *KeyPacketSplitWriter) Keys() crypto.Writer { return sw.keyPacket } func (sw *KeyPacketSplitWriter) Signature() crypto.Writer { return sw.encDetachedSignature } // DetachedSignaturePGPSplitReader implements the crypto.PGPSplitReader interface. type DetachedSignaturePGPSplitReader struct { dataReader crypto.Reader encDetachedSignature crypto.Reader } func NewDetachedSignaturePGPSplitReader(keyPacket []byte, dataReader crypto.Reader, encSignature *crypto.PGPMessage) *DetachedSignaturePGPSplitReader { internalDataReader := io.MultiReader(bytes.NewReader(keyPacket), dataReader) return &DetachedSignaturePGPSplitReader{ dataReader: internalDataReader, encDetachedSignature: encSignature.NewReader(), } } func (ds *DetachedSignaturePGPSplitReader) Read(b []byte) (n int, err error) { return ds.dataReader.Read(b) } func (ds *DetachedSignaturePGPSplitReader) Signature() crypto.Reader { return ds.encDetachedSignature } golang-github-protonmail-gopenpgp-v3-3.1.0/mobile/mobile_stream_test.go000066400000000000000000000237561472137411600262710ustar00rootroot00000000000000package mobile import ( "bytes" "crypto/sha256" "errors" "io" "testing" "github.com/ProtonMail/gopenpgp/v3/constants" "github.com/ProtonMail/gopenpgp/v3/crypto" "github.com/ProtonMail/gopenpgp/v3/profile" ) func cloneTestData() (a, b []byte) { a = []byte("Hello World!") b = clone(a) return a, b } func Test_clone(t *testing.T) { if a, b := cloneTestData(); !bytes.Equal(a, b) { t.Fatalf("expected %x, got %x", a, b) } } func TestMobile2GoWriter(t *testing.T) { testData := []byte("Hello World!") outBuf := &bytes.Buffer{} reader := bytes.NewReader(testData) writer := NewMobile2GoWriter(outBuf) bufSize := 2 writeBuf := make([]byte, bufSize) reachedEnd := false for !reachedEnd { n, err := reader.Read(writeBuf) if err != nil { if errors.Is(err, io.EOF) { reachedEnd = true } else { t.Fatal("Expected no error while reading, got:", err) } } writtenTotal := 0 for writtenTotal < n { written, err := writer.Write(writeBuf[writtenTotal:n]) if err != nil { t.Fatal("Expected no error while writing, got:", err) } writtenTotal += written } } if writtenData := outBuf.Bytes(); !bytes.Equal(testData, writtenData) { t.Fatalf("expected %x, got %x", testData, writtenData) } } func TestMobile2GoWriterWithSHA256(t *testing.T) { testData := []byte("Hello World!") testHash := sha256.Sum256(testData) outBuf := &bytes.Buffer{} reader := bytes.NewReader(testData) writer := NewMobile2GoWriterWithSHA256(outBuf) bufSize := 2 writeBuf := make([]byte, bufSize) reachedEnd := false for !reachedEnd { n, err := reader.Read(writeBuf) if err != nil { if errors.Is(err, io.EOF) { reachedEnd = true } else { t.Fatal("Expected no error while reading, got:", err) } } writtenTotal := 0 for writtenTotal < n { written, err := writer.Write(writeBuf[writtenTotal:n]) if err != nil { t.Fatal("Expected no error while writing, got:", err) } writtenTotal += written } } if writtenData := outBuf.Bytes(); !bytes.Equal(testData, writtenData) { t.Fatalf("expected data to be %x, got %x", testData, writtenData) } if writtenHash := writer.GetSHA256(); !bytes.Equal(testHash[:], writtenHash) { t.Fatalf("expected has to be %x, got %x", testHash, writtenHash) } } func TestGo2AndroidReader(t *testing.T) { testData := []byte("Hello World!") reader := NewGo2AndroidReader(bytes.NewReader(testData)) var readData []byte bufSize := 2 buffer := make([]byte, bufSize) reachedEnd := false for !reachedEnd { n, err := reader.Read(buffer) if err != nil { t.Fatal("Expected no error while reading, got:", err) } reachedEnd = n < 0 if n > 0 { readData = append(readData, buffer[:n]...) } } if !bytes.Equal(testData, readData) { t.Fatalf("expected data to be %x, got %x", testData, readData) } } func TestGo2IOSReader(t *testing.T) { testData := []byte("Hello World!") reader := NewGo2IOSReader(bytes.NewReader(testData)) var readData []byte bufSize := 2 reachedEnd := false for !reachedEnd { res, err := reader.Read(bufSize) if err != nil { t.Fatal("Expected no error while reading, got:", err) } n := res.N reachedEnd = res.IsEOF if n > 0 { readData = append(readData, res.Data[:n]...) } } if !bytes.Equal(testData, readData) { t.Fatalf("expected data to be %x, got %x", testData, readData) } } type testMobileReader struct { reader io.Reader returnError bool } func (r *testMobileReader) Read(max int) (*MobileReadResult, error) { if r.returnError { return nil, errors.New("gopenpgp: test - forced error while reading") } buf := make([]byte, max) n, err := r.reader.Read(buf) eof := false if err != nil { if errors.Is(err, io.EOF) { eof = true } else { return nil, errors.New("gopenpgp: test - error while reading") } } return NewMobileReadResult(n, eof, buf[:n]), nil } func TestMobile2GoReader(t *testing.T) { testData := []byte("Hello World!") reader := NewMobile2GoReader(&testMobileReader{bytes.NewReader(testData), false}) var readData []byte bufSize := 2 readBuf := make([]byte, bufSize) reachedEnd := false for !reachedEnd { n, err := reader.Read(readBuf) if err != nil { if errors.Is(err, io.EOF) { reachedEnd = true } else { t.Fatal("Expected no error while reading, got:", err) } } if n > 0 { readData = append(readData, readBuf[:n]...) } } if !bytes.Equal(testData, readData) { t.Fatalf("expected data to be %x, got %x", testData, readData) } readerErr := NewMobile2GoReader(&testMobileReader{bytes.NewReader(testData), true}) if _, err := readerErr.Read(readBuf); err == nil { t.Fatal("expected an error while reading, got nil") } } func setUpTestKeyRing() (*crypto.PGPHandle, *crypto.KeyRing, *crypto.KeyRing, error) { pgpHandle := crypto.PGPWithProfile(profile.Default()) testKey, err := pgpHandle.KeyGeneration(). AddUserId("test", "test@protonmail.com"). New(). GenerateKey() if err != nil { return nil, nil, nil, err } testPublicKey, err := testKey.ToPublic() if err != nil { return nil, nil, nil, err } testPrivateKeyRing, err := crypto.NewKeyRing(testKey) if err != nil { return nil, nil, nil, err } testPublicKeyRing, err := crypto.NewKeyRing(testPublicKey) if err != nil { return nil, nil, nil, err } return pgpHandle, testPublicKeyRing, testPrivateKeyRing, nil } func TestExplicitVerifyAllGoesWell(t *testing.T) { data := []byte("hello") pgpHandle, pubKR, privKR, err := setUpTestKeyRing() if err != nil { t.Fatalf("Got an error while loading test key: %v", err) } defer privKR.ClearPrivateParams() encHandle, _ := pgpHandle.Encryption().Recipients(pubKR).SigningKeys(privKR).New() ciphertext, err := encHandle.Encrypt(data) if err != nil { t.Fatalf("Got an error while encrypting test data: %v", err) } decHandle, _ := pgpHandle.Decryption().DecryptionKeys(privKR).VerificationKeys(pubKR).New() reader, err := decHandle.DecryptingReader(bytes.NewReader(ciphertext.Bytes()), crypto.Bytes) if err != nil { t.Fatalf("Got an error while decrypting stream data: %v", err) } _, err = io.ReadAll(reader) if err != nil { t.Fatalf("Got an error while reading decrypted data: %v", err) } sigErr, err := reader.VerifySignature() if err != nil { t.Fatalf("Got an error while decrypting: %v", err) } if err = sigErr.SignatureError(); err != nil { t.Fatalf("Got a signature error while verifying embedded sig: %v", err) } if err != nil { t.Fatalf("Got an error while verifying embedded sig: %v", err) } } func TestExplicitVerifyTooEarly(t *testing.T) { data := []byte("hello") pgp, pubKR, privKR, err := setUpTestKeyRing() if err != nil { t.Fatalf("Got an error while loading test key: %v", err) } defer privKR.ClearPrivateParams() encHandle, _ := pgp.Encryption().Recipients(pubKR).SigningKeys(privKR).New() ciphertext, err := encHandle.Encrypt(data) if err != nil { t.Fatalf("Got an error while encrypting test data: %v", err) } decHandle, _ := pgp.Decryption().DecryptionKeys(privKR).VerificationKeys(pubKR).New() reader, err := decHandle.DecryptingReader(bytes.NewReader(ciphertext.Bytes()), crypto.Bytes) if err != nil { t.Fatalf("Got an error while decrypting stream data: %v", err) } buff := make([]byte, 1) _, err = reader.Read(buff) if err != nil { t.Fatalf("Got an error while reading decrypted data: %v", err) } sigErr, err := reader.VerifySignature() if err == nil { t.Fatalf("Got no error while verifying a reader before reading it entirely") } if err = sigErr.SignatureError(); err != nil { t.Fatalf("Got a signature error while verifying embedded sig: %v", sigErr.SignatureError()) } } func TestExplicitVerifyNoSig(t *testing.T) { data := []byte("hello") pgp, pubKR, privKR, err := setUpTestKeyRing() if err != nil { t.Fatalf("Got an error while loading test key: %v", err) } defer privKR.ClearPrivateParams() encHandle, _ := pgp.Encryption().Recipients(pubKR).New() ciphertext, err := encHandle.Encrypt(data) if err != nil { t.Fatalf("Got an error while encrypting test data: %v", err) } decHandle, _ := pgp.Decryption().DecryptionKeys(privKR).VerificationKeys(pubKR).New() reader, err := decHandle.DecryptingReader(bytes.NewReader(ciphertext.Bytes()), crypto.Bytes) if err != nil { t.Fatalf("Got an error while decrypting stream data: %v", err) } _, err = io.ReadAll(reader) if err != nil { t.Fatalf("Got an error while reading decrypted data: %v", err) } sigErr, err := reader.VerifySignature() if err != nil { t.Fatalf("Got an error while verifying embedded sig: %v", err) } if err = sigErr.SignatureError(); err == nil { t.Fatal("Got no signature error while verifying unsigned data") } if sigErr.SignatureErrorExplicit().Status != constants.SIGNATURE_NOT_SIGNED { t.Fatal("Signature error status was not SIGNATURE_NOT_SIGNED") } } func TestExplicitVerifyWrongVerifier(t *testing.T) { data := []byte("hello") pgp, pubKR, privKR, err := setUpTestKeyRing() if err != nil { t.Fatalf("Got an error while loading test key: %v", err) } defer privKR.ClearPrivateParams() _, _, privKR2, err := setUpTestKeyRing() if err != nil { t.Fatalf("Got an error while loading test key: %v", err) } defer privKR2.ClearPrivateParams() encHandle, _ := pgp.Encryption().Recipients(pubKR).SigningKeys(privKR2).New() ciphertext, err := encHandle.Encrypt(data) if err != nil { t.Fatalf("Got an error while encrypting test data: %v", err) } decHandle, _ := pgp.Decryption().DecryptionKeys(privKR).VerificationKeys(pubKR).New() reader, err := decHandle.DecryptingReader(bytes.NewReader(ciphertext.Bytes()), crypto.Bytes) if err != nil { t.Fatalf("Got an error while decrypting stream data: %v", err) } _, err = io.ReadAll(reader) if err != nil { t.Fatalf("Got an error while reading decrypted data: %v", err) } sigErr, err := reader.VerifySignature() if err != nil { t.Fatalf("Got an error while verifying embedded sig: %v", err) } if err = sigErr.SignatureError(); err == nil { t.Fatal("Got no signature error while verifying with wrong key") } if sigErr.SignatureErrorExplicit().Status != constants.SIGNATURE_NO_VERIFIER { t.Fatal("Signature error status was not SIGNATURE_NO_VERIFIER") } } golang-github-protonmail-gopenpgp-v3-3.1.0/profile/000077500000000000000000000000001472137411600222355ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-v3-3.1.0/profile/preset.go000066400000000000000000000042651472137411600240750ustar00rootroot00000000000000package profile import ( "crypto" "github.com/ProtonMail/go-crypto/openpgp/packet" "github.com/ProtonMail/go-crypto/openpgp/s2k" "github.com/ProtonMail/gopenpgp/v3/constants" ) // Default returns a custom profile that support features // that are widely implemented. func Default() *Custom { setKeyAlgorithm := func(cfg *packet.Config, securityLevel int8) { cfg.Algorithm = packet.PubKeyAlgoEdDSA switch securityLevel { case constants.HighSecurity: cfg.Curve = packet.Curve25519 default: cfg.Curve = packet.Curve25519 } } return &Custom{ SetKeyAlgorithm: setKeyAlgorithm, Hash: crypto.SHA256, CipherEncryption: packet.CipherAES256, CompressionAlgorithm: packet.CompressionZLIB, CompressionConfiguration: &packet.CompressionConfig{ Level: 6, }, } } // RFC4880 returns a custom profile for this library // that conforms with the algorithms in RFC4880. func RFC4880() *Custom { setKeyAlgorithm := func(cfg *packet.Config, securityLevel int8) { cfg.Algorithm = packet.PubKeyAlgoRSA switch securityLevel { case constants.HighSecurity: cfg.RSABits = 4096 default: cfg.RSABits = 3072 } } return &Custom{ SetKeyAlgorithm: setKeyAlgorithm, Hash: crypto.SHA256, CipherEncryption: packet.CipherAES256, CompressionAlgorithm: packet.CompressionZLIB, } } // RFC9580 returns a custom profile for this library // that conforms with the algorithms in RFC9580. func RFC9580() *Custom { setKeyAlgorithm := func(cfg *packet.Config, securityLevel int8) { switch securityLevel { case constants.HighSecurity: cfg.Algorithm = packet.PubKeyAlgoEd448 default: cfg.Algorithm = packet.PubKeyAlgoEd25519 } } return &Custom{ SetKeyAlgorithm: setKeyAlgorithm, Hash: crypto.SHA512, CipherEncryption: packet.CipherAES256, CompressionAlgorithm: packet.CompressionZLIB, AeadKeyEncryption: &packet.AEADConfig{}, AeadEncryption: &packet.AEADConfig{}, S2kKeyEncryption: &s2k.Config{ S2KMode: s2k.Argon2S2K, Argon2Config: &s2k.Argon2Config{}, }, S2kEncryption: &s2k.Config{ S2KMode: s2k.Argon2S2K, Argon2Config: &s2k.Argon2Config{}, }, V6: true, } } golang-github-protonmail-gopenpgp-v3-3.1.0/profile/profile.go000066400000000000000000000107261472137411600242320ustar00rootroot00000000000000// Package profile provides different profiles to run GopenPGP. package profile import ( "crypto" "github.com/ProtonMail/go-crypto/openpgp/packet" "github.com/ProtonMail/go-crypto/openpgp/s2k" ) const weakMinRSABits = 1023 // Custom type represents a profile for setting algorithm // parameters for generating keys, encrypting data, and // signing data. // Use one of the pre-defined profiles if possible. // i.e., profile.Default(), profile.RFC4880(). type Custom struct { // SetKeyAlgorithm is a function that sets public key encryption // algorithm in the config bases on the int8 security level. SetKeyAlgorithm func(*packet.Config, int8) // AeadKeyEncryption defines the aead encryption algorithm for key encryption. AeadKeyEncryption *packet.AEADConfig // S2kKeyEncryption defines the s2k algorithm for key encryption. S2kKeyEncryption *s2k.Config // AeadEncryption defines the aead encryption algorithm for pgp encryption. AeadEncryption *packet.AEADConfig // S2kEncryption defines the s2k algorithm for pgp encryption. S2kEncryption *s2k.Config // CompressionConfiguration defines the compression configuration to be used if any. CompressionConfiguration *packet.CompressionConfig // Hash defines hash algorithm to be used. Hash crypto.Hash // SignHash defines if a different hash algorithm should be used for signing. // If nil, the a above field Hash is used. SignHash *crypto.Hash // CipherKeyEncryption defines the cipher to be used for key encryption. CipherKeyEncryption packet.CipherFunction // CipherEncryption defines the cipher to be used for pgp message encryption. CipherEncryption packet.CipherFunction // CompressionAlgorithm defines the compression algorithm to be used if any. CompressionAlgorithm packet.CompressionAlgo // V6 is a flag to indicate if v6 from the crypto-refresh should be used. V6 bool // AllowAllPublicKeyAlgorithms is a flag to disable all checks for deprecated public key algorithms. AllowAllPublicKeyAlgorithms bool // DisableIntendedRecipients is a flag to disable the intended recipients pgp feature from the crypto-refresh. DisableIntendedRecipients bool // InsecureAllowWeakRSA is a flag to disable checks for weak rsa keys. InsecureAllowWeakRSA bool // InsecureAllowDecryptionWithSigningKeys is a flag to enable to decrypt with signing keys for compatibility reasons. InsecureAllowDecryptionWithSigningKeys bool } // Custom implements the profile interfaces: // KeyGenerationProfile, KeyEncryptionProfile, EncryptionProfile, and SignProfile func (p *Custom) KeyGenerationConfig(securityLevel int8) *packet.Config { cfg := &packet.Config{ DefaultHash: p.Hash, DefaultCipher: p.CipherEncryption, AEADConfig: p.AeadEncryption, DefaultCompressionAlgo: p.CompressionAlgorithm, CompressionConfig: p.CompressionConfiguration, V6Keys: p.V6, } p.SetKeyAlgorithm(cfg, securityLevel) return cfg } func (p *Custom) EncryptionConfig() *packet.Config { config := &packet.Config{ DefaultHash: p.Hash, DefaultCipher: p.CipherEncryption, AEADConfig: p.AeadEncryption, S2KConfig: p.S2kEncryption, InsecureAllowDecryptionWithSigningKeys: p.InsecureAllowDecryptionWithSigningKeys, } if p.DisableIntendedRecipients { intendedRecipients := false config.CheckIntendedRecipients = &intendedRecipients } if p.AllowAllPublicKeyAlgorithms { config.RejectPublicKeyAlgorithms = map[packet.PublicKeyAlgorithm]bool{} } if p.InsecureAllowWeakRSA { config.MinRSABits = weakMinRSABits } return config } func (p *Custom) KeyEncryptionConfig() *packet.Config { return &packet.Config{ DefaultHash: p.Hash, DefaultCipher: p.CipherKeyEncryption, AEADConfig: p.AeadKeyEncryption, S2KConfig: p.S2kKeyEncryption, } } func (p *Custom) SignConfig() *packet.Config { config := &packet.Config{ DefaultHash: p.Hash, } if p.SignHash != nil { config.DefaultHash = *p.SignHash } if p.DisableIntendedRecipients { intendedRecipients := false config.CheckIntendedRecipients = &intendedRecipients } if p.AllowAllPublicKeyAlgorithms { config.RejectPublicKeyAlgorithms = map[packet.PublicKeyAlgorithm]bool{} } if p.InsecureAllowWeakRSA { config.MinRSABits = weakMinRSABits } return config } func (p *Custom) CompressionConfig() *packet.Config { return &packet.Config{ CompressionConfig: p.CompressionConfiguration, DefaultCompressionAlgo: p.CompressionAlgorithm, } }