pax_global_header00006660000000000000000000000064147213734360014524gustar00rootroot0000000000000052 comment=5be727a6f0dcb73dfb951bcb2b4bf11740af0cf0 golang-github-protonmail-gopenpgp-2.8.1/000077500000000000000000000000001472137343600202625ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-2.8.1/.github/000077500000000000000000000000001472137343600216225ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-2.8.1/.github/actions/000077500000000000000000000000001472137343600232625ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-2.8.1/.github/actions/build-gosop/000077500000000000000000000000001472137343600255065ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-2.8.1/.github/actions/build-gosop/action.yml000066400000000000000000000031131472137343600275040ustar00rootroot00000000000000name: '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-2.8.1/.github/test-suite/000077500000000000000000000000001472137343600237305ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-2.8.1/.github/test-suite/build_gosop.sh000077500000000000000000000004331472137343600265750ustar00rootroot00000000000000VERSION=$(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-2.8.1/.github/test-suite/config.json.template000066400000000000000000000006621472137343600277060ustar00rootroot00000000000000{ "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-2.8.1/.github/test-suite/determine_gosop_branch.sh000077500000000000000000000003271472137343600307710ustar00rootroot00000000000000VERSION=$(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-2.8.1/.github/test-suite/prepare_config.sh000077500000000000000000000006061472137343600272540ustar00rootroot00000000000000CONFIG_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-2.8.1/.github/workflows/000077500000000000000000000000001472137343600236575ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-2.8.1/.github/workflows/android.yml000066400000000000000000000016501472137343600260240ustar00rootroot00000000000000name: Gomobile for Android on: push: branches: [ main ] pull_request: branches: [ main, v2 ] 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-2.8.1/.github/workflows/go.yml000066400000000000000000000017451472137343600250160ustar00rootroot00000000000000name: Go test and lint on: push: branches: [ main ] pull_request: branches: [ main, v2 ] 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.50.1 golang-github-protonmail-gopenpgp-2.8.1/.github/workflows/ios.yml000066400000000000000000000015431472137343600251770ustar00rootroot00000000000000name: Gomobile for iOS on: push: branches: [ main ] pull_request: branches: [ main, v2 ] jobs: build: name: Build library for iOS with gomobile runs-on: macos-latest steps: - name: Set up xcode 14.3 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-2.8.1/.github/workflows/sop-test-suite.yml000066400000000000000000000102151472137343600273060ustar00rootroot00000000000000name: SOP interoperability test suite on: pull_request: branches: [ main, v2 ] 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.7 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-2.8.1/.gitignore000066400000000000000000000000771472137343600222560ustar00rootroot00000000000000.DS_Store bin dist vendor .vscode *.out *.html reports .idea v2golang-github-protonmail-gopenpgp-2.8.1/.golangci.yml000066400000000000000000000051411472137343600226470ustar00rootroot00000000000000linters-settings: godox: keywords: # default keywords are TODO, BUG, and FIXME, but we override this by ignoring TODO - BUG - FIXME funlen: lines: 100 statements: 80 cyclop: # the minimal code complexity to report max-complexity: 20 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 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 golang-github-protonmail-gopenpgp-2.8.1/CHANGELOG.md000066400000000000000000001305471472137343600221050ustar00rootroot00000000000000# 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). ## [2.8.1] 2024-11-25 ### Changed - Update go-crypto to `1.1.3`. ## [2.8.0] 2024-10-07 ### Changed - Update go-crypto to `1.1.0`. ## [2.8.0-beta.0] 2024-10-01 ### Added - Add `GetSHA256Fingerprint` method to `Key`. ### Changed - Update go-crypto to `1.1.0-beta.0`. ## [2.8.0-alpha.1] 2024-04-09 ### 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) ``` ## [2.8.0-alpha.0] 2024-02-28 ### Added - Adds support for the OpenPGP crypto-refresh by updating the go-crypto dependency to `v1.1.0-alpha.1`. - Adapts the session key logic to handle PKESK/SKESK v6 packets without an algorithm attached - Updates the min go version to `1.17` as required by go-crypto `v1.1.0-alpha.1`. - Update the cricl dependency to `1.3.7` matching go-crypto. ## [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-2.8.1/LICENSE000066400000000000000000000020751472137343600212730ustar00rootroot00000000000000(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-2.8.1/README.md000066400000000000000000000265231472137343600215510ustar00rootroot00000000000000# GopenPGP V2 [![Build Status](https://travis-ci.org/ProtonMail/gopenpgp.svg?branch=master)](https://travis-ci.org/ProtonMail/gopenpgp) GopenPGP is a high-level OpenPGP library built on top of [a fork of the golang crypto library](https://github.com/ProtonMail/crypto). **Table of Contents** - [Download/Install](#downloadinstall) - [Documentation](#documentation) - [Using with Go Mobile](#using-with-go-mobile) - [Full documentation](#full-documentation) - [Examples](#examples) - [Set up](#set-up) - [Encrypt / Decrypt with password](#encrypt--decrypt-with-password) - [Encrypt / Decrypt with PGP keys](#encrypt--decrypt-with-pgp-keys) - [Generate key](#generate-key) - [Detached signatures for plain text messages](#detached-signatures-for-plain-text-messages) - [Detached signatures for binary data](#detached-signatures-for-binary-data) - [Cleartext signed messages](#cleartext-signed-messages) ## Download/Install ### Vendored install To use this library using [Go Modules](https://github.com/golang/go/wiki/Modules) just edit your `go.mod` configuration to contain: ```gomod require ( ... github.com/ProtonMail/gopenpgp/v2 v2.0.1 ) ``` It can then be installed by running: ```sh go mod vendor ``` Finally your software can include it in your software as follows: ```go package main import ( "fmt" "github.com/ProtonMail/gopenpgp/v2/crypto" ) func main() { fmt.Println(crypto.GetUnixTime()) } ``` ### Git-Clone install To install for development mode, cloning the repository, it can be done in the following way: ```bash cd $GOPATH mkdir -p src/github.com/ProtonMail/ cd $GOPATH/src/github.com/ProtonMail/ git clone git@github.com:ProtonMail/gopenpgp.git cd gopenpgp ln -s . v2 go mod ``` ## Documentation A full overview of the API can be found here: https://godoc.org/gopkg.in/ProtonMail/gopenpgp.v2/crypto In this document examples are provided and the proper use of (almost) all functions is tested. ## 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. ## Examples ### Encrypt / Decrypt with password ```go import "github.com/ProtonMail/gopenpgp/v2/helper" const password = []byte("hunter2") // Encrypt data with password armor, err := helper.EncryptMessageWithPassword(password, "my message") // Decrypt data with password message, err := helper.DecryptMessageWithPassword(password, armor) ``` To encrypt binary data or use more advanced modes: ```go import "github.com/ProtonMail/gopenpgp/v2/constants" const password = []byte("hunter2") var message = crypto.NewPlainMessage(data) // Or message = crypto.NewPlainMessageFromString(string) // Encrypt data with password encrypted, err := EncryptMessageWithPassword(message, password) // Encrypted message in encrypted.GetBinary() or encrypted.GetArmored() // Decrypt data with password decrypted, err := DecryptMessageWithPassword(encrypted, password) //Original message in decrypted.GetBinary() ``` ### Encrypt / Decrypt with PGP keys ```go import "github.com/ProtonMail/gopenpgp/v2/helper" // 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 // encrypt plain text message using public key armor, err := helper.EncryptMessageArmored(pubkey, "plain text") // decrypt armored encrypted message using the private key and obtain plain text decrypted, err := helper.DecryptMessageArmored(privkey, passphrase, armor) // encrypt binary message using public key armor, err := helper.EncryptBinaryMessageArmored(pubkey, []byte("plain text")) // decrypt armored encrypted message using the private key expecting binary data decrypted, err := helper.DecryptBinaryMessageArmored(privkey, passphrase, armor) ``` With signatures: ```go // Keys initialization as before (omitted) // encrypt message using public key, sign with the private key armor, err := helper.EncryptSignMessageArmored(pubkey, privkey, passphrase, "plain text") // decrypt armored encrypted message using the private key, verify with the public key // err != nil if verification fails decrypted, err := helper.DecryptVerifyMessageArmored(pubkey, privkey, passphrase, armor) ``` For more advanced modes the full API (i.e. without helpers) can be used: ```go // Keys initialization as before (omitted) var binMessage = crypto.NewPlainMessage(data) publicKeyObj, err := crypto.NewKeyFromArmored(publicKey) publicKeyRing, err := crypto.NewKeyRing(publicKeyObj) pgpMessage, err := publicKeyRing.Encrypt(binMessage, privateKeyRing) // Armored message in pgpMessage.GetArmored() // pgpMessage can be obtained from NewPGPMessageFromArmored(ciphertext) //pgpMessage can be obtained from a byte array var pgpMessage = crypto.NewPGPMessage([]byte) privateKeyObj, err := crypto.NewKeyFromArmored(privateKey) unlockedKeyObj = privateKeyObj.Unlock(passphrase) privateKeyRing, err := crypto.NewKeyRing(unlockedKeyObj) message, err := privateKeyRing.Decrypt(pgpMessage, publicKeyRing, crypto.GetUnixTime()) privateKeyRing.ClearPrivateParams() // Original data in message.GetString() // `err` can be a SignatureVerificationError ``` ### Generate key Keys are generated with the `GenerateKey` function, that returns the armored key as a string and a potential error. The library supports RSA with different key lengths or Curve25519 keys. ```go const ( name = "Max Mustermann" email = "max.mustermann@example.com" passphrase = []byte("LongSecret") rsaBits = 2048 ) // RSA, string rsaKey, err := helper.GenerateKey(name, email, passphrase, "rsa", rsaBits) // Curve25519, string ecKey, err := helper.GenerateKey(name, email, passphrase, "x25519", 0) // RSA, Key struct rsaKey, err := crypto.GenerateKey(name, email, "rsa", rsaBits) // Curve25519, Key struct ecKey, err := crypto.GenerateKey(name, email, "x25519", 0) ``` ### Detached signatures for plain text messages To sign plain text data either an unlocked private keyring or a passphrase must be provided. The output is an armored signature. ```go const privkey = `-----BEGIN PGP PRIVATE KEY BLOCK----- ... -----END PGP PRIVATE KEY BLOCK-----` // Encrypted private key const passphrase = []byte("LongSecret") // Private key passphrase var message = crypto.NewPlaintextMessage("Verified message") privateKeyObj, err := crypto.NewKeyFromArmored(privkey) unlockedKeyObj = privateKeyObj.Unlock(passphrase) signingKeyRing, err := crypto.NewKeyRing(unlockedKeyObj) pgpSignature, err := signingKeyRing.SignDetached(message, trimNewlines) // The armored signature is in pgpSignature.GetArmored() // The signed text is in message.GetString() ``` To verify a signature either private or public keyring can be provided. ```go const pubkey = `-----BEGIN PGP PUBLIC KEY BLOCK----- ... -----END PGP PUBLIC KEY BLOCK-----` const signature = `-----BEGIN PGP SIGNATURE----- ... -----END PGP SIGNATURE-----` message := crypto.NewPlaintextMessage("Verified message") pgpSignature, err := crypto.NewPGPSignatureFromArmored(signature) publicKeyObj, err := crypto.NewKeyFromArmored(pubkey) signingKeyRing, err := crypto.NewKeyRing(publicKeyObj) err := signingKeyRing.VerifyDetached(message, pgpSignature, crypto.GetUnixTime()) if err == nil { // verification success } ``` ### Detached signatures for binary data ```go const privkey = `-----BEGIN PGP PRIVATE KEY BLOCK----- ... -----END PGP PRIVATE KEY BLOCK-----` // encrypted private key const passphrase = "LongSecret" var message = crypto.NewPlainMessage(data) privateKeyObj, err := crypto.NewKeyFromArmored(privkey) unlockedKeyObj := privateKeyObj.Unlock(passphrase) signingKeyRing, err := crypto.NewKeyRing(unlockedKeyObj) pgpSignature, err := signingKeyRing.SignDetached(message) // The armored signature is in pgpSignature.GetArmored() // The signed text is in message.GetBinary() ``` To verify a signature either private or public keyring can be provided. ```go const pubkey = `-----BEGIN PGP PUBLIC KEY BLOCK----- ... -----END PGP PUBLIC KEY BLOCK-----` const signature = `-----BEGIN PGP SIGNATURE----- ... -----END PGP SIGNATURE-----` message := crypto.NewPlainMessage("Verified message") pgpSignature, err := crypto.NewPGPSignatureFromArmored(signature) publicKeyObj, err := crypto.NewKeyFromArmored(pubkey) signingKeyRing, err := crypto.NewKeyRing(publicKeyObj) err := signingKeyRing.VerifyDetached(message, pgpSignature, crypto.GetUnixTime()) if err == nil { // verification success } ``` ### Cleartext signed messages ```go // Keys initialization as before (omitted) armored, err := helper.SignCleartextMessageArmored(privateKey, passphrase, plaintext) ``` To verify the message it has to be provided unseparated to the library. If verification fails an error will be returned. ```go // Keys initialization as before (omitted) verifiedPlainText, err := helper.VerifyCleartextMessageArmored(publicKey, armored, crypto.GetUnixTime()) ``` ### Encrypting and decrypting session Keys A session key can be generated, encrypted to a Asymmetric/Symmetric key packet and obtained from it ```go // Keys initialization as before (omitted) sessionKey, err := crypto.GenerateSessionKey() keyPacket, err := publicKeyRing.EncryptSessionKey(sessionKey) // Will encrypt to all the keys in the keyring keyPacketSymm, err := crypto.EncryptSessionKeyWithPassword(sessionKey, password) ``` `KeyPacket` is a `[]byte` containing the session key encrypted with the public key or password. ```go decodedKeyPacket, err := privateKeyRing.DecryptSessionKey(keyPacket) // Will decode with the first valid key found decodedSymmKeyPacket, err := crypto.DecryptSessionKeyWithPassword(keyPacketSymm, password) ``` `decodedKeyPacket` and `decodedSymmKeyPacket` are objects of type `*SymmetricKey` that can be used to decrypt the corresponding symmetrically encrypted data packets: ```go var message = crypto.NewPlainMessage(data) // Encrypt data with session key dataPacket, err := sessionKey.Encrypt(message) // Decrypt data with session key decrypted, err := sessionKey.Decrypt(password, dataPacket) //Original message in decrypted.GetBinary() ``` Note that it is not possible to process signatures when using data packets directly. Joining the data packet and a key packet gives us a valid PGP message: ```go pgpSplitMessage := NewPGPSplitMessage(keyPacket, dataPacket) pgpMessage := pgpSplitMessage.GetPGPMessage() // And vice-versa newPGPSplitMessage, err := pgpMessage.SeparateKeyAndData() // Key Packet is in newPGPSplitMessage.GetBinaryKeyPacket() // Data Packet is in newPGPSplitMessage.GetBinaryDataPacket() ``` ### Checking keys Keys are now checked on import and the explicit check via `Key#Check()` is deprecated and no longer necessary.golang-github-protonmail-gopenpgp-2.8.1/armor/000077500000000000000000000000001472137343600214025ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-2.8.1/armor/armor.go000066400000000000000000000040401472137343600230470ustar00rootroot00000000000000// Package armor contains a set of helper methods for armoring and unarmoring // data. package armor import ( "bytes" "io" "io/ioutil" "github.com/ProtonMail/go-crypto/openpgp/armor" "github.com/ProtonMail/gopenpgp/v2/constants" "github.com/ProtonMail/gopenpgp/v2/internal" "github.com/pkg/errors" ) // ArmorKey armors input as a public key. func ArmorKey(input []byte) (string, error) { return ArmorWithType(input, constants.PublicKeyHeader) } // ArmorWithTypeBuffered returns a io.WriteCloser which, when written to, writes // armored data to w with the given armorType. func ArmorWithTypeBuffered(w io.Writer, armorType string) (io.WriteCloser, error) { return armor.Encode(w, armorType, nil) } // ArmorWithType armors input with the given armorType. func ArmorWithType(input []byte, armorType string) (string, error) { return armorWithTypeAndHeaders(input, armorType, internal.ArmorHeaders) } // ArmorWithTypeAndCustomHeaders armors input with the given armorType and // headers. func ArmorWithTypeAndCustomHeaders(input []byte, armorType, version, comment string) (string, error) { headers := make(map[string]string) if version != "" { headers["Version"] = version } if comment != "" { headers["Comment"] = comment } return armorWithTypeAndHeaders(input, armorType, headers) } // 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, "gopengp: unable to unarmor") } return ioutil.ReadAll(b.Body) } func armorWithTypeAndHeaders(input []byte, armorType string, headers map[string]string) (string, error) { var b bytes.Buffer w, err := armor.Encode(&b, armorType, headers) if err != nil { return "", errors.Wrap(err, "gopengp: unable to encode armoring") } if _, err = w.Write(input); err != nil { return "", errors.Wrap(err, "gopengp: unable to write armored to buffer") } if err := w.Close(); err != nil { return "", errors.Wrap(err, "gopengp: unable to close armor buffer") } return b.String(), nil } golang-github-protonmail-gopenpgp-2.8.1/build.sh000077500000000000000000000057401472137343600217260ustar00rootroot00000000000000#!/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/v2/crypto import github.com/ProtonMail/gopenpgp/v2/armor import github.com/ProtonMail/gopenpgp/v2/constants import github.com/ProtonMail/gopenpgp/v2/models import github.com/ProtonMail/gopenpgp/v2/subtle import github.com/ProtonMail/gopenpgp/v2/helper ######## ======== 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-2.8.1/constants/000077500000000000000000000000001472137343600222765ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-2.8.1/constants/armor.go000066400000000000000000000005661472137343600237540ustar00rootroot00000000000000// Package constants provides a set of common OpenPGP constants. package constants // Constants for armored data. const ( ArmorHeaderVersion = "GopenPGP 2.8.1" ArmorHeaderComment = "https://gopenpgp.org" PGPMessageHeader = "PGP MESSAGE" PGPSignatureHeader = "PGP SIGNATURE" PublicKeyHeader = "PGP PUBLIC KEY BLOCK" PrivateKeyHeader = "PGP PRIVATE KEY BLOCK" ) golang-github-protonmail-gopenpgp-2.8.1/constants/cipher.go000066400000000000000000000007771472137343600241120ustar00rootroot00000000000000package 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 ) const DefaultCompression = 2 // ZLIB const DefaultCompressionLevel = 6 // Corresponds to default -1 for ZLIB golang-github-protonmail-gopenpgp-2.8.1/constants/context.go000066400000000000000000000001041472137343600243040ustar00rootroot00000000000000package constants const SignatureContextName = "context@proton.ch" golang-github-protonmail-gopenpgp-2.8.1/constants/version.go000066400000000000000000000000531472137343600243100ustar00rootroot00000000000000package constants const Version = "2.8.1" golang-github-protonmail-gopenpgp-2.8.1/crypto/000077500000000000000000000000001472137343600216025ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-2.8.1/crypto/attachment.go000066400000000000000000000120631472137343600242630ustar00rootroot00000000000000package crypto import ( "bytes" "io" "io/ioutil" "runtime" "sync" "time" "github.com/ProtonMail/go-crypto/openpgp" "github.com/ProtonMail/go-crypto/openpgp/packet" "github.com/pkg/errors" ) // AttachmentProcessor keeps track of the progress of encrypting an attachment // (optimized for encrypting large files). type AttachmentProcessor struct { w *io.WriteCloser pipe *io.PipeWriter done sync.WaitGroup split *PGPSplitMessage garbageCollector int err error } // Process writes attachment data to be encrypted. func (ap *AttachmentProcessor) Process(plainData []byte) { if _, err := (*ap.w).Write(plainData); err != nil { panic(err) } if ap.garbageCollector > 0 { defer runtime.GC() } } // Finish closes the attachment and returns the encrypted data. func (ap *AttachmentProcessor) Finish() (*PGPSplitMessage, error) { if ap.err != nil { return nil, ap.err } if err := (*ap.w).Close(); err != nil { return nil, errors.Wrap(err, "gopengpp: unable to close writer") } if ap.garbageCollector > 0 { ap.w = nil runtime.GC() } if err := (*ap.pipe).Close(); err != nil { return nil, errors.Wrap(err, "gopengpp: unable to close pipe") } ap.done.Wait() if ap.err != nil { return nil, ap.err } splitMsg := ap.split if ap.garbageCollector > 0 { ap.pipe = nil ap.split = nil defer runtime.GC() } return splitMsg, nil } // newAttachmentProcessor creates an AttachmentProcessor which can be used to encrypt // a file. It takes an estimatedSize and fileName as hints about the file. func (keyRing *KeyRing) newAttachmentProcessor( estimatedSize int, filename string, isBinary bool, modTime uint32, garbageCollector int, //nolint:unparam ) (*AttachmentProcessor, error) { attachmentProc := &AttachmentProcessor{} // You could also add these one at a time if needed. attachmentProc.done.Add(1) attachmentProc.garbageCollector = garbageCollector hints := &openpgp.FileHints{ FileName: filename, IsBinary: isBinary, ModTime: time.Unix(int64(modTime), 0), } config := &packet.Config{ DefaultCipher: packet.CipherAES256, Time: getTimeGenerator(), } reader, writer := io.Pipe() go func() { defer attachmentProc.done.Done() ciphertext, _ := ioutil.ReadAll(reader) message := &PGPMessage{ Data: ciphertext, } split, splitError := message.SplitMessage() if attachmentProc.err == nil { attachmentProc.err = splitError } attachmentProc.split = split }() var ew io.WriteCloser var encryptErr error ew, encryptErr = openpgp.Encrypt(writer, keyRing.entities, nil, hints, config) if encryptErr != nil { return nil, errors.Wrap(encryptErr, "gopengpp: unable to encrypt attachment") } attachmentProc.w = &ew attachmentProc.pipe = writer return attachmentProc, nil } // EncryptAttachment encrypts a file given a PlainMessage and a filename. // If given a filename it will override the information in the PlainMessage object. // Returns a PGPSplitMessage containing a session key packet and symmetrically encrypted data. // Specifically designed for attachments rather than text messages. func (keyRing *KeyRing) EncryptAttachment(message *PlainMessage, filename string) (*PGPSplitMessage, error) { if filename == "" { filename = message.Filename } ap, err := keyRing.newAttachmentProcessor( len(message.GetBinary()), filename, message.IsBinary(), message.Time, -1, ) if err != nil { return nil, err } ap.Process(message.GetBinary()) split, err := ap.Finish() if err != nil { return nil, err } return split, nil } // NewLowMemoryAttachmentProcessor creates an AttachmentProcessor which can be used // to encrypt a file. It takes an estimatedSize and filename as hints about the // file. It is optimized for low-memory environments and collects garbage every // megabyte. func (keyRing *KeyRing) NewLowMemoryAttachmentProcessor( estimatedSize int, filename string, ) (*AttachmentProcessor, error) { return keyRing.newAttachmentProcessor(estimatedSize, filename, true, uint32(GetUnixTime()), 1<<20) } // DecryptAttachment takes a PGPSplitMessage, containing a session key packet and symmetrically encrypted data // and returns a decrypted PlainMessage // Specifically designed for attachments rather than text messages. func (keyRing *KeyRing) DecryptAttachment(message *PGPSplitMessage) (*PlainMessage, error) { privKeyEntries := keyRing.entities keyReader := bytes.NewReader(message.GetBinaryKeyPacket()) dataReader := bytes.NewReader(message.GetBinaryDataPacket()) encryptedReader := io.MultiReader(keyReader, dataReader) config := &packet.Config{Time: getTimeGenerator()} md, err := openpgp.ReadMessage(encryptedReader, privKeyEntries, nil, config) if err != nil { return nil, errors.Wrap(err, "gopengpp: unable to read attachment") } decrypted := md.UnverifiedBody b, err := ioutil.ReadAll(decrypted) if err != nil { return nil, errors.Wrap(err, "gopengpp: unable to read attachment body") } return &PlainMessage{ Data: b, TextType: !md.LiteralData.IsBinary, Filename: md.LiteralData.FileName, Time: md.LiteralData.Time, }, nil } golang-github-protonmail-gopenpgp-2.8.1/crypto/attachment_manual.go000066400000000000000000000126131472137343600256210ustar00rootroot00000000000000package crypto import ( "io" "io/ioutil" "runtime" "runtime/debug" "sync" "time" "github.com/ProtonMail/go-crypto/openpgp" "github.com/ProtonMail/go-crypto/openpgp/packet" "github.com/pkg/errors" ) // ManualAttachmentProcessor keeps track of the progress of encrypting an attachment // (optimized for encrypting large files). // With this processor, the caller has to first allocate // a buffer large enough to hold the whole data packet. type ManualAttachmentProcessor struct { keyPacket []byte dataLength int plaintextWriter io.WriteCloser ciphertextWriter *io.PipeWriter err error done sync.WaitGroup } // GetKeyPacket returns the key packet for the attachment. // This should be called only after Finish() has been called. func (ap *ManualAttachmentProcessor) GetKeyPacket() []byte { return ap.keyPacket } // GetDataLength returns the number of bytes in the DataPacket. // This should be called only after Finish() has been called. func (ap *ManualAttachmentProcessor) GetDataLength() int { return ap.dataLength } // Process writes attachment data to be encrypted. func (ap *ManualAttachmentProcessor) Process(plainData []byte) error { defer runtime.GC() _, err := ap.plaintextWriter.Write(plainData) return errors.Wrap(err, "gopenpgp: couldn't write attachment data") } // Finish tells the processor to finalize encryption. func (ap *ManualAttachmentProcessor) Finish() error { defer runtime.GC() if ap.err != nil { return ap.err } if err := ap.plaintextWriter.Close(); err != nil { return errors.Wrap(err, "gopengpp: unable to close the plaintext writer") } if err := ap.ciphertextWriter.Close(); err != nil { return errors.Wrap(err, "gopengpp: unable to close the dataPacket writer") } ap.done.Wait() if ap.err != nil { return ap.err } return nil } // NewManualAttachmentProcessor creates an AttachmentProcessor which can be used // to encrypt a file. It takes an estimatedSize and filename as hints about the // file and a buffer to hold the DataPacket. // It is optimized for low-memory environments and collects garbage every megabyte. // The buffer for the data packet must be manually allocated by the caller. // Make sure that the dataBuffer is large enough to hold the whole data packet // otherwise Finish() will return an error. func (keyRing *KeyRing) NewManualAttachmentProcessor( estimatedSize int, filename string, dataBuffer []byte, ) (*ManualAttachmentProcessor, error) { if len(dataBuffer) == 0 { return nil, errors.New("gopenpgp: can't give a nil or empty buffer to process the attachment") } // forces the gc to be called often debug.SetGCPercent(10) attachmentProc := &ManualAttachmentProcessor{} // hints for the encrypted file isBinary := true modTime := GetUnixTime() hints := &openpgp.FileHints{ FileName: filename, IsBinary: isBinary, ModTime: time.Unix(modTime, 0), } // encryption config config := &packet.Config{ DefaultCipher: packet.CipherAES256, Time: getTimeGenerator(), } // goroutine that reads the key packet // to be later returned to the caller via GetKeyPacket() keyReader, keyWriter := io.Pipe() attachmentProc.done.Add(1) go func() { defer attachmentProc.done.Done() keyPacket, err := ioutil.ReadAll(keyReader) if err != nil { attachmentProc.err = err } else { attachmentProc.keyPacket = clone(keyPacket) } }() // goroutine that reads the data packet into the provided buffer dataReader, dataWriter := io.Pipe() attachmentProc.done.Add(1) go func() { defer attachmentProc.done.Done() totalRead, err := readAll(dataBuffer, dataReader) if err != nil { attachmentProc.err = err } else { attachmentProc.dataLength = totalRead } }() // We generate the encrypting writer var ew io.WriteCloser var encryptErr error ew, encryptErr = openpgp.EncryptSplit(keyWriter, dataWriter, keyRing.entities, nil, hints, config) if encryptErr != nil { return nil, errors.Wrap(encryptErr, "gopengpp: unable to encrypt attachment") } attachmentProc.plaintextWriter = ew attachmentProc.ciphertextWriter = dataWriter // The key packet should have been already written, so we can close if err := keyWriter.Close(); err != nil { return nil, errors.Wrap(err, "gopenpgp: couldn't close the keyPacket writer") } // Check if the goroutines encountered errors if attachmentProc.err != nil { return nil, attachmentProc.err } return attachmentProc, nil } // readAll works a bit like ioutil.ReadAll // but we can choose the buffer to write to // and we don't grow the slice in case of overflow. func readAll(buffer []byte, reader io.Reader) (int, error) { bufferLen := len(buffer) totalRead := 0 offset := 0 overflow := false reset := false for { // We read into the buffer n, err := reader.Read(buffer[offset:]) totalRead += n offset += n if !overflow && reset && n != 0 { // In case we've started overwriting the beginning of the buffer // We will return an error at Finish() overflow = true } if err != nil { if errors.Is(err, io.EOF) { break } return 0, errors.Wrap(err, "gopenpgp: couldn't read data from the encrypted reader") } if offset == bufferLen { // Here we've reached the end of the buffer // But we need to keep reading to not block the Process() // So we reset the buffer reset = true offset = 0 } } if overflow { return 0, errors.New("gopenpgp: read more bytes that was allocated in the buffer") } return totalRead, nil } golang-github-protonmail-gopenpgp-2.8.1/crypto/attachment_manual_test.go000066400000000000000000000122371472137343600266620ustar00rootroot00000000000000package crypto import ( "bytes" "io" "testing" "github.com/pkg/errors" ) func TestManualAttachmentProcessor(t *testing.T) { pgp.latestServerTime = 1615394034 defer func() { pgp.latestServerTime = testTime }() passphrase := []byte("wUMuF/lkDPYWH/0ZqqY8kJKw7YJg6kS") pk, err := NewKeyFromArmored(readTestFile("att_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()) } inputPlaintext := readTestFile("att_cleartext", false) plaintextBytes := []byte(inputPlaintext) plaintextReader := bytes.NewReader(plaintextBytes) bufferLen := 2 * len(plaintextBytes) dataPacket := make([]byte, bufferLen) ap, err := ukr.NewManualAttachmentProcessor( len(plaintextBytes), "test.txt", dataPacket, ) if err != nil { t.Error("Expected no error while building the attachment processor, got:" + err.Error()) } chunkSize := 1 << 10 inputBytes := make([]byte, chunkSize) var readAllPlaintext = false for !readAllPlaintext { nBytesRead, err := plaintextReader.Read(inputBytes) if errors.Is(err, io.EOF) { readAllPlaintext = true } else if err != nil { t.Error("Expected no error while reading plain data, got:" + err.Error()) } err = ap.Process(inputBytes[:nBytesRead]) if err != nil { t.Error("Expected no error while writing plain data, got:" + err.Error()) } } err = ap.Finish() if err != nil { t.Error("Expected no error while calling finish, got:" + err.Error()) } dataLength := ap.GetDataLength() keyPacket := ap.GetKeyPacket() if keyPacket == nil { t.Error("The key packet was nil") } if len(keyPacket) == 0 { t.Error("The key packet was empty") } t.Logf("buffer size : %d total written : %d", bufferLen, dataLength) if dataLength > bufferLen { t.Errorf("Wrote more than was allocated, buffer size : %d total written : %d", bufferLen, dataLength) } pgpMsg := NewPGPSplitMessage(keyPacket, dataPacket[:dataLength]).GetPGPMessage() plainMsg, err := ukr.Decrypt(pgpMsg, nil, 0) if err != nil { t.Error("Expected no error while decrypting, got:" + err.Error()) } outputPlaintext := string(plainMsg.Data) if outputPlaintext != inputPlaintext { t.Errorf("Expectedplaintext to be %s got %s", inputPlaintext, outputPlaintext) } } func TestManualAttachmentProcessorNotEnoughBuffer(t *testing.T) { pgp.latestServerTime = 1615394034 defer func() { pgp.latestServerTime = testTime }() passphrase := []byte("wUMuF/lkDPYWH/0ZqqY8kJKw7YJg6kS") pk, err := NewKeyFromArmored(readTestFile("att_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()) } inputPlaintext := readTestFile("att_cleartext", false) plaintextBytes := []byte(inputPlaintext) plaintextReader := bytes.NewReader(plaintextBytes) bufferLen := len(plaintextBytes) / 2 dataPacket := make([]byte, bufferLen) ap, err := ukr.NewManualAttachmentProcessor( len(plaintextBytes), "test.txt", dataPacket, ) if err != nil { t.Error("Expected no error while building the attachment processor, got:" + err.Error()) } chunkSize := 1 << 10 inputBytes := make([]byte, chunkSize) var readAllPlaintext = false for !readAllPlaintext { nBytesRead, err := plaintextReader.Read(inputBytes) if errors.Is(err, io.EOF) { readAllPlaintext = true } else if err != nil { t.Error("Expected no error while reading plain data, got:" + err.Error()) } err = ap.Process(inputBytes[:nBytesRead]) if err != nil { t.Error("Expected no error while writing plain data, got:" + err.Error()) } } err = ap.Finish() if err == nil { t.Error("Expected an error while calling finish, got nil") } } func TestManualAttachmentProcessorEmptyBuffer(t *testing.T) { pgp.latestServerTime = 1615394034 defer func() { pgp.latestServerTime = testTime }() passphrase := []byte("wUMuF/lkDPYWH/0ZqqY8kJKw7YJg6kS") pk, err := NewKeyFromArmored(readTestFile("att_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()) } inputPlaintext := readTestFile("att_cleartext", false) plaintextBytes := []byte(inputPlaintext) bufferLen := 0 dataPacket := make([]byte, bufferLen) _, err = ukr.NewManualAttachmentProcessor( len(plaintextBytes), "test.txt", dataPacket, ) if err == nil { t.Error("Expected an error while building the attachment processor with an empty buffer got nil") } } golang-github-protonmail-gopenpgp-2.8.1/crypto/attachment_test.go000066400000000000000000000105731472137343600253260ustar00rootroot00000000000000package crypto import ( "encoding/base64" "testing" "github.com/stretchr/testify/assert" ) // const testAttachmentEncrypted = // `0ksB0fHC6Duezx/0TqpK/82HSl8+qCY0c2BCuyrSFoj6Dubd93T3//32jVYa624NYvfvxX+UxFKYKJxG09gFsU1IVc87cWvUgmUmgjU=` var testAttachmentKey, _ = base64.StdEncoding.DecodeString("ExXmnSiQ2QCey20YLH6qlLhkY3xnIBC1AwlIXwK/HvY=") func TestAttachmentGetKey(t *testing.T) { testKeyPacketsDecoded, err := base64.StdEncoding.DecodeString(readTestFile("attachment_keypacket", false)) if err != nil { t.Fatal("Expected no error while decoding base64 KeyPacket, got:", err) } sessionKey, err := keyRingTestPrivate.DecryptSessionKey(testKeyPacketsDecoded) if err != nil { t.Fatal("Expected no error while decrypting KeyPacket, got:", err) } assert.Exactly(t, testAttachmentKey, sessionKey.Key) } func TestAttachmentSetKey(t *testing.T) { keyPackets, err := keyRingTestPublic.EncryptSessionKey(testSessionKey) if err != nil { t.Fatal("Expected no error while encrypting attachment key, got:", err) } sessionKey, err := keyRingTestPrivate.DecryptSessionKey(keyPackets) if err != nil { t.Fatal("Expected no error while decrypting attachment key, got:", err) } assert.Exactly(t, testSessionKey, sessionKey) } func TestAttachmentEncryptDecrypt(t *testing.T) { var testAttachmentCleartext = "cc,\ndille." var message = NewPlainMessageFromFile([]byte(testAttachmentCleartext), "test.txt", 1602518992) encSplit, err := keyRingTestPrivate.EncryptAttachment(message, "") if err != nil { t.Fatal("Expected no error while encrypting attachment, got:", err) } redecData, err := keyRingTestPrivate.DecryptAttachment(encSplit) if err != nil { t.Fatal("Expected no error while decrypting attachment, got:", err) } assert.Exactly(t, message, redecData) } func TestAttachmentEncrypt(t *testing.T) { var testAttachmentCleartext = "cc,\ndille." var message = NewPlainMessageFromFile([]byte(testAttachmentCleartext), "test.txt", 1602518992) encSplit, err := keyRingTestPrivate.EncryptAttachment(message, "") if err != nil { t.Fatal("Expected no error while encrypting attachment, got:", err) } pgpMessage := NewPGPMessage(encSplit.GetBinary()) redecData, err := keyRingTestPrivate.Decrypt(pgpMessage, nil, 0) if err != nil { t.Fatal("Expected no error while decrypting attachment, got:", err) } assert.Exactly(t, message, redecData) } func TestAttachmentDecrypt(t *testing.T) { var testAttachmentCleartext = "cc,\ndille." var message = NewPlainMessageFromFile([]byte(testAttachmentCleartext), "test.txt", 1602518992) encrypted, err := keyRingTestPrivate.Encrypt(message, nil) if err != nil { t.Fatal("Expected no error while encrypting attachment, got:", err) } armored, err := encrypted.GetArmored() if err != nil { t.Fatal("Expected no error while armoring, got:", err) } pgpSplitMessage, err := NewPGPSplitMessageFromArmored(armored) if err != nil { t.Fatal("Expected no error while unarmoring, got:", err) } redecData, err := keyRingTestPrivate.DecryptAttachment(pgpSplitMessage) if err != nil { t.Fatal("Expected no error while decrypting attachment, got:", err) } assert.Exactly(t, message, redecData) } func TestAttachmentDecryptStatic(t *testing.T) { passphrase := []byte("wUMuF/lkDPYWH/0ZqqY8kJKw7YJg6kS") keyPacket, err := base64.StdEncoding.DecodeString(readTestFile("att_keypacket", false)) if err != nil { t.Error("Expected no error while decoding key packet, got:" + err.Error()) } dataPacket, err := base64.StdEncoding.DecodeString(readTestFile("att_body", false)) if err != nil { t.Error("Expected no error while decoding data packet, got:" + err.Error()) } pk, err := NewKeyFromArmored(readTestFile("att_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()) } pgpSplitMessage := NewPGPSplitMessage(keyPacket, dataPacket) if err != nil { t.Fatal("Expected no error while unarmoring, got:", err) } dec, err := ukr.DecryptAttachment(pgpSplitMessage) if err != nil { t.Fatal("Expected no error while decrypting attachment, got:", err) } assert.Exactly(t, []byte("PNG"), dec.GetBinary()[1:4]) } golang-github-protonmail-gopenpgp-2.8.1/crypto/base_test.go000066400000000000000000000032061472137343600241030ustar00rootroot00000000000000package crypto import ( "crypto/rsa" "io/ioutil" "math/big" "strings" "testing" "github.com/ProtonMail/go-crypto/openpgp/ecdh" "github.com/ProtonMail/go-crypto/openpgp/eddsa" "github.com/stretchr/testify/assert" ) const testTime = 1557754627 // 2019-05-13T13:37:07+00:00 func readTestFile(name string, trimNewlines bool) string { data, err := ioutil.ReadFile("testdata/" + name) //nolint if err != nil { panic(err) } if trimNewlines { return strings.TrimRight(string(data), "\n") } return string(data) } func init() { UpdateTime(testTime) // 2019-05-13T13:37:07+00:00 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-2.8.1/crypto/gopenpgp.go000066400000000000000000000013001472137343600237420ustar00rootroot00000000000000// Package crypto provides a high-level API for common OpenPGP functionality. package crypto import "sync" // GopenPGP is used as a "namespace" for many of the functions in this package. // It is a struct that keeps track of time skew between server and client. type GopenPGP struct { latestServerTime int64 generationOffset int64 lock *sync.RWMutex } var pgp = GopenPGP{ latestServerTime: 0, generationOffset: 0, lock: &sync.RWMutex{}, } // 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-2.8.1/crypto/key.go000066400000000000000000000315661472137343600227340ustar00rootroot00000000000000package crypto import ( "bytes" "crypto" "crypto/sha256" "encoding/hex" "fmt" "io" "math/big" "strconv" "strings" "github.com/ProtonMail/gopenpgp/v2/armor" "github.com/ProtonMail/gopenpgp/v2/constants" "github.com/pkg/errors" openpgp "github.com/ProtonMail/go-crypto/openpgp" packet "github.com/ProtonMail/go-crypto/openpgp/packet" ) // Key contains a single private or public key. type Key struct { // PGP entities in this keyring. entity *openpgp.Entity } // --- Create Key object // NewKeyFromArmoredReader reads an armored data into a key. func NewKeyFromArmoredReader(r io.Reader) (key *Key, err error) { key = &Key{} err = key.readFrom(r, true) if err != nil { return nil, err } return key, nil } // NewKeyFromReader reads binary data into a Key object. func NewKeyFromReader(r io.Reader) (key *Key, err error) { key = &Key{} err = key.readFrom(r, false) if err != nil { return nil, err } return key, nil } // NewKey creates a new key from the first key in the unarmored binary data. func NewKey(binKeys []byte) (key *Key, err error) { return NewKeyFromReader(bytes.NewReader(clone(binKeys))) } // NewKeyFromArmored creates a new key from the first key in an armored string. func NewKeyFromArmored(armored string) (key *Key, err error) { return NewKeyFromArmoredReader(strings.NewReader(armored)) } func NewKeyFromEntity(entity *openpgp.Entity) (*Key, error) { if entity == nil { return nil, errors.New("gopenpgp: nil entity provided") } return &Key{entity: entity}, nil } // GenerateRSAKeyWithPrimes generates a RSA key using the given primes. func GenerateRSAKeyWithPrimes( name, email string, bits int, primeone, primetwo, primethree, primefour []byte, ) (*Key, error) { return generateKey(name, email, "rsa", bits, primeone, primetwo, primethree, primefour) } // GenerateKey generates a key of the given keyType ("rsa" or "x25519"). // If keyType is "rsa", bits is the RSA bitsize of the key. // If keyType is "x25519" bits is unused. func GenerateKey(name, email string, keyType string, bits int) (*Key, error) { return generateKey(name, email, keyType, bits, nil, nil, nil, nil) } // --- 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) (*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 } if lockedKey.entity.PrivateKey != nil && !lockedKey.entity.PrivateKey.Dummy() { err = lockedKey.entity.PrivateKey.Encrypt(passphrase) if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in locking key") } } for _, sub := range lockedKey.entity.Subkeys { if sub.PrivateKey != nil && !sub.PrivateKey.Dummy() { if err := sub.PrivateKey.Encrypt(passphrase); err != nil { return nil, errors.Wrap(err, "gopenpgp: error in locking sub 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 } if unlockedKey.entity.PrivateKey != nil && !unlockedKey.entity.PrivateKey.Dummy() { err = unlockedKey.entity.PrivateKey.Decrypt(passphrase) if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in unlocking key") } } for _, sub := range unlockedKey.entity.Subkeys { if sub.PrivateKey != nil && !sub.PrivateKey.Dummy() { if err := sub.PrivateKey.Decrypt(passphrase); err != nil { return nil, errors.Wrap(err, "gopenpgp: error in unlocking sub 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.ArmorWithType(serialized, constants.PrivateKeyHeader) } return armor.ArmorWithType(serialized, constants.PublicKeyHeader) } // 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.ArmorWithTypeAndCustomHeaders(serialized, constants.PrivateKeyHeader, version, comment) } // 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.ArmorWithType(serialized, constants.PublicKeyHeader) } // 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.ArmorWithTypeAndCustomHeaders(serialized, constants.PublicKeyHeader, version, comment) } // 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() bool { _, canVerify := key.entity.SigningKey(getNow()) return canVerify } // CanEncrypt returns true if any of the subkeys can be used for encryption. func (key *Key) CanEncrypt() bool { _, canEncrypt := key.entity.EncryptionKey(getNow()) return canEncrypt } // IsExpired checks whether the key is expired. func (key *Key) IsExpired() bool { i := key.entity.PrimaryIdentity() return key.entity.PrimaryKey.KeyExpired(i.SelfSignature, getNow()) || // primary key has expired i.SelfSignature.SigExpired(getNow()) // user ID self-signature has expired } // IsRevoked checks whether the key or the primary identity has a valid revocation signature. func (key *Key) IsRevoked() bool { return key.entity.Revoked(getNow()) || key.entity.PrimaryIdentity().Revoked(getNow()) } // 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 true, 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 { if !subKey.Sig.FlagsValid || subKey.Sig.FlagEncryptStorage || subKey.Sig.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. 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) } // 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 } // GetEntity gets x/crypto Entity object. func (key *Key) GetEntity() *openpgp.Entity { return key.entity } // 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 } // --- 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 generateKey( name, email string, keyType string, bits int, prime1, prime2, prime3, prime4 []byte, ) (*Key, error) { if len(email) == 0 && len(name) == 0 { return nil, errors.New("gopenpgp: neither name nor email set.") } comments := "" cfg := &packet.Config{ Algorithm: packet.PubKeyAlgoRSA, RSABits: bits, Time: getKeyGenerationTimeGenerator(), DefaultHash: crypto.SHA256, DefaultCipher: packet.CipherAES256, DefaultCompressionAlgo: packet.CompressionZLIB, } if keyType == "x25519" { cfg.Algorithm = packet.PubKeyAlgoEdDSA } if prime1 != nil && prime2 != nil && prime3 != nil && prime4 != nil { var bigPrimes [4]*big.Int bigPrimes[0] = new(big.Int) bigPrimes[0].SetBytes(prime1) bigPrimes[1] = new(big.Int) bigPrimes[1].SetBytes(prime2) bigPrimes[2] = new(big.Int) bigPrimes[2].SetBytes(prime3) bigPrimes[3] = new(big.Int) bigPrimes[3].SetBytes(prime4) cfg.RSAPrimes = bigPrimes[:] } newEntity, err := openpgp.NewEntity(name, comments, email, cfg) 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-2.8.1/crypto/key_clear.go000066400000000000000000000066501472137343600240760ustar00rootroot00000000000000package crypto import ( "crypto/dsa" //nolint:staticcheck "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" ) func (sk *SessionKey) Clear() (ok bool) { clearMem(sk.Key) return true } 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-2.8.1/crypto/key_test.go000066400000000000000000000310421472137343600237600ustar00rootroot00000000000000package crypto import ( "crypto/rsa" "encoding/base64" "io/ioutil" "regexp" "strings" "testing" "github.com/ProtonMail/go-crypto/openpgp" "github.com/ProtonMail/go-crypto/openpgp/armor" "github.com/ProtonMail/go-crypto/openpgp/packet" "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 keyTestRSA, err = GenerateKey(keyTestName, keyTestDomain, "rsa", 1024) if err != nil { panic("Cannot generate RSA key:" + err.Error()) } keyTestEC, err = GenerateKey(keyTestName, keyTestDomain, "x25519", 256) if err != nil { panic("Cannot generate EC key:" + err.Error()) } } func initArmoredKeys() { var err error lockedRSA, err := keyTestRSA.Lock(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 := keyTestEC.Lock(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-----.*Version: GopenPGP [0-9]+\.[0-9]+\.[0-9]+.*-----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 = publicKey.Lock(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 := unlockedKey.Lock(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.Exactly(t, false, keyTestRSA.IsExpired()) assert.Exactly(t, false, keyTestEC.IsExpired()) 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.Exactly(t, true, expiredKey.IsExpired()) assert.Exactly(t, true, futureKey.IsExpired()) } func TestGenerateKeyWithPrimes(t *testing.T) { prime1, _ := base64.StdEncoding.DecodeString( "/thF8zjjk6fFx/y9NId35NFx8JTA7jvHEl+gI0dp9dIl9trmeZb+ESZ8f7bNXUmTI8j271kyenlrVJiqwqk80Q==") prime2, _ := base64.StdEncoding.DecodeString( "0HyyG/TShsw7yObD+DDP9Ze39ye1Redljx+KOZ3iNDmuuwwI1/5y44rD/ezAsE7A188NsotMDTSy5xtfHmu0xQ==") prime3, _ := base64.StdEncoding.DecodeString( "3OyJpAdnQXNjPNzI1u3BWDmPrzWw099E0UfJj5oJJILSbsAg/DDrmrdrIZDt7f24d06HCnTErCNWjvFJ3Kdq4w==") prime4, _ := base64.StdEncoding.DecodeString( "58UEDXTX29Q9JqvuE3Tn+Qj275CXBnJbA8IVM4d05cPYAZ6H43bPN01pbJqJTJw/cuFxs+8C+HNw3/MGQOExqw==") staticRsaKey, err := GenerateRSAKeyWithPrimes(keyTestName, keyTestDomain, 1024, prime1, prime2, prime3, prime4) if err != nil { t.Fatal("Cannot generate RSA key with primes:", err) } pk, ok := staticRsaKey.entity.PrivateKey.PrivateKey.(*rsa.PrivateKey) assert.True(t, ok) assert.Exactly(t, prime1, pk.Primes[0].Bytes()) assert.Exactly(t, prime2, pk.Primes[1].Bytes()) } func TestFailCheckIntegrity25519(t *testing.T) { failCheckIntegrity(t, "x25519", 0) } func TestFailCheckIntegrityRSA(t *testing.T) { failCheckIntegrity(t, "rsa", 2048) } func failCheckIntegrity(t *testing.T, keyType string, bits int) { k1, _ := GenerateKey(keyTestName, keyTestDomain, keyType, bits) k2, _ := GenerateKey(keyTestName, keyTestDomain, keyType, bits) k1.entity.PrivateKey.PrivateKey = k2.entity.PrivateKey.PrivateKey // Swap private keys serialized, err := k1.Serialize() if err != nil { t.Fatal("Expected no error while serializing keyring, got:", err) } _, err = NewKey(serialized) assert.Error(t, err) } 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 := ioutil.ReadAll(block.Body) if err != nil { t.Fatal("Expected no error while reading armored public key body, got:", err) } eb, err := ioutil.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()) assert.Contains(t, publicKey, "Version: GopenPGP") 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() assert.True(t, entity.PrimaryIdentity().SelfSignature.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()) assert.True(t, keyTestEC.CanEncrypt()) assert.True(t, keyTestRSA.CanVerify()) assert.True(t, keyTestRSA.CanEncrypt()) publicKey, err := keyTestEC.ToPublic() if err != nil { t.Fatal("Cannot make key public:", err) } assert.True(t, publicKey.CanVerify()) assert.True(t, publicKey.CanEncrypt()) } func TestRevokedKeyCapabilities(t *testing.T) { pgp.latestServerTime = 1632219895 defer func() { pgp.latestServerTime = testTime }() revokedKey, err := NewKeyFromArmored(readTestFile("key_revoked", false)) if err != nil { t.Fatal("Cannot unarmor key:", err) } assert.False(t, revokedKey.CanVerify()) assert.False(t, revokedKey.CanEncrypt()) assert.False(t, revokedKey.IsExpired()) assert.True(t, revokedKey.IsRevoked()) } 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) { assert.Equal( t, []uint8{uint8(packet.CompressionNone), uint8(packet.CompressionZLIB)}, keyTestEC.entity.PrimaryIdentity().SelfSignature.PreferredCompression, ) } golang-github-protonmail-gopenpgp-2.8.1/crypto/keyring.go000066400000000000000000000166441472137343600236140ustar00rootroot00000000000000package crypto import ( "bytes" "time" "github.com/ProtonMail/go-crypto/openpgp" "github.com/ProtonMail/go-crypto/openpgp/packet" "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 Email string } // --- 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. 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 } // getSigningEntity returns first private unlocked signing entity from keyring. func (keyRing *KeyRing) getSigningEntity() (*openpgp.Entity, error) { var signEntity *openpgp.Entity for _, e := range keyRing.entities { // Entity.PrivateKey must be a signing key if e.PrivateKey != nil { if !e.PrivateKey.Encrypted { signEntity = e break } } } if signEntity == nil { return nil, errors.New("gopenpgp: cannot sign message, unable to unlock signer key") } return signEntity, nil } // 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 { return len(keyRing.entities) } // CountDecryptionEntities returns the number of entities in the keyring. func (keyRing *KeyRing) CountDecryptionEntities() int { return len(keyRing.entities.DecryptionKeys()) } // GetIdentities returns the list of identities associated with this key ring. 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 } // CanVerify returns true if any of the keys in the keyring can be used for verification. func (keyRing *KeyRing) CanVerify() bool { keys := keyRing.GetKeys() for _, key := range keys { if key.CanVerify() { return true } } return false } // CanEncrypt returns true if any of the keys in the keyring can be used for encryption. func (keyRing *KeyRing) CanEncrypt() bool { keys := keyRing.GetKeys() for _, key := range keys { if key.CanEncrypt() { return true } } return false } // GetKeyIDs returns array of IDs of keys in this KeyRing. 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 } // --- 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 //nolint:ifshort 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 { if subkey.PublicKey.KeyExpired(subkey.Sig, 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-2.8.1/crypto/keyring_message.go000066400000000000000000000303561472137343600253140ustar00rootroot00000000000000package crypto import ( "bytes" "io" "io/ioutil" "time" "github.com/ProtonMail/go-crypto/openpgp" "github.com/ProtonMail/go-crypto/openpgp/packet" "github.com/ProtonMail/gopenpgp/v2/constants" "github.com/pkg/errors" ) // Encrypt encrypts a PlainMessage, outputs a PGPMessage. // If an unlocked private key is also provided it will also sign the message. // * message : The plaintext input as a PlainMessage. // * privateKey : (optional) an unlocked private keyring to include signature in the message. func (keyRing *KeyRing) Encrypt(message *PlainMessage, privateKey *KeyRing) (*PGPMessage, error) { return asymmetricEncrypt(message, keyRing, privateKey, false, nil) } // EncryptWithContext encrypts a PlainMessage, outputs a PGPMessage. // If an unlocked private key is also provided it will also sign the message. // * message : The plaintext input as a PlainMessage. // * privateKey : (optional) an unlocked private keyring to include signature in the message. // * signingContext : (optional) the context for the signature. func (keyRing *KeyRing) EncryptWithContext(message *PlainMessage, privateKey *KeyRing, signingContext *SigningContext) (*PGPMessage, error) { return asymmetricEncrypt(message, keyRing, privateKey, false, signingContext) } // EncryptWithCompression encrypts with compression support a PlainMessage to PGPMessage using public/private keys. // * message : The plain data as a PlainMessage. // * privateKey : (optional) an unlocked private keyring to include signature in the message. // * output : The encrypted data as PGPMessage. func (keyRing *KeyRing) EncryptWithCompression(message *PlainMessage, privateKey *KeyRing) (*PGPMessage, error) { return asymmetricEncrypt(message, keyRing, privateKey, true, nil) } // EncryptWithContextAndCompression encrypts with compression support a PlainMessage to PGPMessage using public/private keys. // * message : The plain data as a PlainMessage. // * privateKey : (optional) an unlocked private keyring to include signature in the message. // * signingContext : (optional) the context for the signature. // * output : The encrypted data as PGPMessage. func (keyRing *KeyRing) EncryptWithContextAndCompression(message *PlainMessage, privateKey *KeyRing, signingContext *SigningContext) (*PGPMessage, error) { return asymmetricEncrypt(message, keyRing, privateKey, true, signingContext) } // Decrypt decrypts encrypted string using pgp keys, returning a PlainMessage // * message : The encrypted input as a PGPMessage // * verifyKey : Public key for signature verification (optional) // * verifyTime : Time at verification (necessary only if verifyKey is not nil) // * verificationContext : (optional) the context for the signature verification. // // When verifyKey is not provided, then verifyTime should be zero, and // signature verification will be ignored. func (keyRing *KeyRing) Decrypt( message *PGPMessage, verifyKey *KeyRing, verifyTime int64, ) (*PlainMessage, error) { return asymmetricDecrypt(message.NewReader(), keyRing, verifyKey, verifyTime, nil) } // DecryptWithContext decrypts encrypted string using pgp keys, returning a PlainMessage // * message : The encrypted input as a PGPMessage // * verifyKey : Public key for signature verification (optional) // * verifyTime : Time at verification (necessary only if verifyKey is not nil) // * verificationContext : (optional) the context for the signature verification. // // When verifyKey is not provided, then verifyTime should be zero, and // signature verification will be ignored. func (keyRing *KeyRing) DecryptWithContext( message *PGPMessage, verifyKey *KeyRing, verifyTime int64, verificationContext *VerificationContext, ) (*PlainMessage, error) { return asymmetricDecrypt(message.NewReader(), keyRing, verifyKey, verifyTime, verificationContext) } // SignDetached generates and returns a PGPSignature for a given PlainMessage. func (keyRing *KeyRing) SignDetached(message *PlainMessage) (*PGPSignature, error) { return keyRing.SignDetachedWithContext(message, nil) } // SignDetachedWithContext generates and returns a PGPSignature for a given PlainMessage. // If a context is provided, it is added to the signature as notation data // with the name set in `constants.SignatureContextName`. func (keyRing *KeyRing) SignDetachedWithContext(message *PlainMessage, context *SigningContext) (*PGPSignature, error) { return signMessageDetached( keyRing, message.NewReader(), message.IsBinary(), context, ) } // VerifyDetached verifies a PlainMessage with a detached PGPSignature // and returns a SignatureVerificationError if fails. func (keyRing *KeyRing) VerifyDetached(message *PlainMessage, signature *PGPSignature, verifyTime int64) error { _, err := verifySignature( keyRing.entities, message.NewReader(), signature.GetBinary(), verifyTime, nil, ) return err } // VerifyDetachedWithContext verifies a PlainMessage with a detached PGPSignature // and returns a SignatureVerificationError if fails. // If a context is provided, it verifies that the signature is valid in the given context, using // the signature notation with name the name set in `constants.SignatureContextName`. func (keyRing *KeyRing) VerifyDetachedWithContext(message *PlainMessage, signature *PGPSignature, verifyTime int64, verificationContext *VerificationContext) error { _, err := verifySignature( keyRing.entities, message.NewReader(), signature.GetBinary(), verifyTime, verificationContext, ) return err } // SignDetachedEncrypted generates and returns a PGPMessage // containing an encrypted detached signature for a given PlainMessage. func (keyRing *KeyRing) SignDetachedEncrypted(message *PlainMessage, encryptionKeyRing *KeyRing) (encryptedSignature *PGPMessage, err error) { if encryptionKeyRing == nil { return nil, errors.New("gopenpgp: no encryption key ring provided") } signature, err := keyRing.SignDetached(message) if err != nil { return nil, err } plainMessage := NewPlainMessage(signature.GetBinary()) encryptedSignature, err = encryptionKeyRing.Encrypt(plainMessage, nil) return } // VerifyDetachedEncrypted verifies a PlainMessage // with a PGPMessage containing an encrypted detached signature // and returns a SignatureVerificationError if fails. func (keyRing *KeyRing) VerifyDetachedEncrypted(message *PlainMessage, encryptedSignature *PGPMessage, decryptionKeyRing *KeyRing, verifyTime int64) error { if decryptionKeyRing == nil { return errors.New("gopenpgp: no decryption key ring provided") } plainMessage, err := decryptionKeyRing.Decrypt(encryptedSignature, nil, 0) if err != nil { return err } signature := NewPGPSignature(plainMessage.GetBinary()) return keyRing.VerifyDetached(message, signature, verifyTime) } // GetVerifiedSignatureTimestamp verifies a PlainMessage with a detached PGPSignature // returns the creation time of the signature if it succeeds // and returns a SignatureVerificationError if fails. func (keyRing *KeyRing) GetVerifiedSignatureTimestamp(message *PlainMessage, signature *PGPSignature, verifyTime int64) (int64, error) { sigPacket, err := verifySignature( keyRing.entities, message.NewReader(), signature.GetBinary(), verifyTime, nil, ) if err != nil { return 0, err } return sigPacket.CreationTime.Unix(), nil } // GetVerifiedSignatureTimestampWithContext verifies a PlainMessage with a detached PGPSignature // returns the creation time of the signature if it succeeds // and returns a SignatureVerificationError if fails. // If a context is provided, it verifies that the signature is valid in the given context, using // the signature notation with name the name set in `constants.SignatureContextName`. func (keyRing *KeyRing) GetVerifiedSignatureTimestampWithContext( message *PlainMessage, signature *PGPSignature, verifyTime int64, verificationContext *VerificationContext, ) (int64, error) { sigPacket, err := verifySignature( keyRing.entities, message.NewReader(), signature.GetBinary(), verifyTime, verificationContext, ) if err != nil { return 0, err } return sigPacket.CreationTime.Unix(), nil } // ------ INTERNAL FUNCTIONS ------- // Core for encryption+signature (non-streaming) functions. func asymmetricEncrypt( plainMessage *PlainMessage, publicKey, privateKey *KeyRing, compress bool, signingContext *SigningContext, ) (*PGPMessage, error) { var outBuf bytes.Buffer var encryptWriter io.WriteCloser var err error hints := &openpgp.FileHints{ IsBinary: plainMessage.IsBinary(), FileName: plainMessage.Filename, ModTime: plainMessage.getFormattedTime(), } encryptWriter, err = asymmetricEncryptStream(hints, &outBuf, &outBuf, publicKey, privateKey, compress, signingContext) if err != nil { return nil, err } _, err = encryptWriter.Write(plainMessage.GetBinary()) if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in writing to message") } err = encryptWriter.Close() if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in closing message") } return &PGPMessage{outBuf.Bytes()}, nil } // Core for encryption+signature (all) functions. func asymmetricEncryptStream( hints *openpgp.FileHints, keyPacketWriter io.Writer, dataPacketWriter io.Writer, publicKey, privateKey *KeyRing, compress bool, signingContext *SigningContext, ) (encryptWriter io.WriteCloser, err error) { config := &packet.Config{ DefaultCipher: packet.CipherAES256, Time: getTimeGenerator(), } if compress { config.DefaultCompressionAlgo = constants.DefaultCompression config.CompressionConfig = &packet.CompressionConfig{Level: constants.DefaultCompressionLevel} } if signingContext != nil { config.SignatureNotations = append(config.SignatureNotations, signingContext.getNotation()) } var signEntity *openpgp.Entity if privateKey != nil && len(privateKey.entities) > 0 { var err error signEntity, err = privateKey.getSigningEntity() if err != nil { return nil, err } } if hints.IsBinary { encryptWriter, err = openpgp.EncryptSplit(keyPacketWriter, dataPacketWriter, publicKey.entities, signEntity, hints, config) } else { encryptWriter, err = openpgp.EncryptTextSplit(keyPacketWriter, dataPacketWriter, publicKey.entities, signEntity, hints, config) } if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in encrypting asymmetrically") } return encryptWriter, nil } // Core for decryption+verification (non streaming) functions. func asymmetricDecrypt( encryptedIO io.Reader, privateKey *KeyRing, verifyKey *KeyRing, verifyTime int64, verificationContext *VerificationContext, ) (message *PlainMessage, err error) { messageDetails, err := asymmetricDecryptStream( encryptedIO, privateKey, verifyKey, verifyTime, verificationContext, ) if err != nil { return nil, err } body, err := ioutil.ReadAll(messageDetails.UnverifiedBody) if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in reading message body") } if verifyKey != nil { processSignatureExpiration(messageDetails, verifyTime) err = verifyDetailsSignature(messageDetails, verifyKey, verificationContext) } return &PlainMessage{ Data: body, TextType: !messageDetails.LiteralData.IsBinary, Filename: messageDetails.LiteralData.FileName, Time: messageDetails.LiteralData.Time, }, err } // Core for decryption+verification (all) functions. func asymmetricDecryptStream( encryptedIO io.Reader, privateKey *KeyRing, verifyKey *KeyRing, verifyTime int64, verificationContext *VerificationContext, ) (messageDetails *openpgp.MessageDetails, err error) { privKeyEntries := privateKey.entities var additionalEntries openpgp.EntityList if verifyKey != nil { additionalEntries = verifyKey.entities } if additionalEntries != nil { privKeyEntries = append(privKeyEntries, additionalEntries...) } config := &packet.Config{ Time: func() time.Time { if verifyTime == 0 { /* We default to current time while decrypting and verifying but the caller will remove signature expiration errors later on. See processSignatureExpiration(). */ return getNow() } return time.Unix(verifyTime, 0) }, } if verificationContext != nil { config.KnownNotations = map[string]bool{constants.SignatureContextName: true} } messageDetails, err = openpgp.ReadMessage(encryptedIO, privKeyEntries, nil, config) if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in reading message") } return messageDetails, err } golang-github-protonmail-gopenpgp-2.8.1/crypto/keyring_message_test.go000066400000000000000000000044761472137343600263570ustar00rootroot00000000000000package crypto import ( "io/ioutil" "testing" "github.com/stretchr/testify/assert" ) func TestAEADKeyRingDecryption(t *testing.T) { pgpMessageData, err := ioutil.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() decrypted, err := kR.Decrypt(pgpMessage, nil, 0) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, "hello world\n", decrypted.GetString()) } func TestTextMessageEncryptionWithSignatureAndContext(t *testing.T) { var message = NewPlainMessageFromString("plain text") var testContext = "test-context" ciphertext, err := keyRingTestPublic.EncryptWithContext(message, keyRingTestPrivate, NewSigningContext(testContext, true)) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } decrypted, err := keyRingTestPrivate.DecryptWithContext( ciphertext, keyRingTestPublic, GetUnixTime(), NewVerificationContext(testContext, true, 0), ) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, message.GetString(), decrypted.GetString()) } func TestTextMessageEncryptionWithSignatureAndContextAndCompression(t *testing.T) { var message = NewPlainMessageFromString("plain text") var testContext = "test-context" ciphertext, err := keyRingTestPublic.EncryptWithContextAndCompression(message, keyRingTestPrivate, NewSigningContext(testContext, true)) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } decrypted, err := keyRingTestPrivate.DecryptWithContext( ciphertext, keyRingTestPublic, GetUnixTime(), NewVerificationContext(testContext, true, 0), ) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, message.GetString(), decrypted.GetString()) } golang-github-protonmail-gopenpgp-2.8.1/crypto/keyring_session.go000066400000000000000000000050011472137343600253400ustar00rootroot00000000000000package crypto import ( "bytes" "strconv" "github.com/pkg/errors" "github.com/ProtonMail/go-crypto/openpgp/packet" ) // DecryptSessionKey returns the decrypted session key from one or multiple binary encrypted session key packets. func (keyRing *KeyRing) DecryptSessionKey(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 for _, key := range keyRing.entities.DecryptionKeys() { 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 (keyRing *KeyRing) EncryptSessionKey(sk *SessionKey) ([]byte, error) { outbuf := &bytes.Buffer{} cf, err := sk.GetCipherFunc() if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to encrypt session key") } pubKeys := make([]*packet.PublicKey, 0, len(keyRing.entities)) for _, e := range keyRing.entities { encryptionKey, ok := e.EncryptionKey(getNow()) if !ok { return nil, errors.New("gopenpgp: encryption key is unavailable for key id " + strconv.FormatUint(e.PrimaryKey.KeyId, 16)) } pubKeys = append(pubKeys, encryptionKey.PublicKey) } if len(pubKeys) == 0 { return nil, errors.New("cannot set key: no public key available") } for _, pub := range pubKeys { if err := packet.SerializeEncryptedKey(outbuf, pub, cf, sk.Key, nil); err != nil { return nil, errors.Wrap(err, "gopenpgp: cannot set key") } } return outbuf.Bytes(), nil } golang-github-protonmail-gopenpgp-2.8.1/crypto/keyring_streaming.go000066400000000000000000000400601472137343600256520ustar00rootroot00000000000000package crypto import ( "bytes" "io" "time" "github.com/ProtonMail/go-crypto/openpgp" "github.com/pkg/errors" ) type Reader interface { Read(b []byte) (n int, err error) } type Writer interface { Write(b []byte) (n int, err error) } type WriteCloser interface { Write(b []byte) (n int, err error) Close() (err error) } type PlainMessageMetadata struct { IsBinary bool Filename string ModTime int64 } func NewPlainMessageMetadata(isBinary bool, filename string, modTime int64) *PlainMessageMetadata { return &PlainMessageMetadata{IsBinary: isBinary, Filename: filename, ModTime: modTime} } // EncryptStream is used to encrypt data as a Writer. // It takes a writer for the encrypted data and returns a WriteCloser for the plaintext data // If signKeyRing is not nil, it is used to do an embedded signature. func (keyRing *KeyRing) EncryptStream( pgpMessageWriter Writer, plainMessageMetadata *PlainMessageMetadata, signKeyRing *KeyRing, ) (plainMessageWriter WriteCloser, err error) { return encryptStream( keyRing, pgpMessageWriter, pgpMessageWriter, plainMessageMetadata, signKeyRing, false, nil, ) } // EncryptStreamWithContext is used to encrypt data as a Writer. // It takes a writer for the encrypted data and returns a WriteCloser for the plaintext data // If signKeyRing is not nil, it is used to do an embedded signature. // * signingContext : (optional) a context for the embedded signature. func (keyRing *KeyRing) EncryptStreamWithContext( pgpMessageWriter Writer, plainMessageMetadata *PlainMessageMetadata, signKeyRing *KeyRing, signingContext *SigningContext, ) (plainMessageWriter WriteCloser, err error) { return encryptStream( keyRing, pgpMessageWriter, pgpMessageWriter, plainMessageMetadata, signKeyRing, false, signingContext, ) } // EncryptStreamWithCompression is used to encrypt data as a Writer. // The plaintext data is compressed before being encrypted. // It takes a writer for the encrypted data and returns a WriteCloser for the plaintext data // If signKeyRing is not nil, it is used to do an embedded signature. func (keyRing *KeyRing) EncryptStreamWithCompression( pgpMessageWriter Writer, plainMessageMetadata *PlainMessageMetadata, signKeyRing *KeyRing, ) (plainMessageWriter WriteCloser, err error) { return encryptStream( keyRing, pgpMessageWriter, pgpMessageWriter, plainMessageMetadata, signKeyRing, true, nil, ) } // EncryptStreamWithContextAndCompression is used to encrypt data as a Writer. // The plaintext data is compressed before being encrypted. // It takes a writer for the encrypted data and returns a WriteCloser for the plaintext data // If signKeyRing is not nil, it is used to do an embedded signature. // * signingContext : (optional) a context for the embedded signature. func (keyRing *KeyRing) EncryptStreamWithContextAndCompression( pgpMessageWriter Writer, plainMessageMetadata *PlainMessageMetadata, signKeyRing *KeyRing, signingContext *SigningContext, ) (plainMessageWriter WriteCloser, err error) { return encryptStream( keyRing, pgpMessageWriter, pgpMessageWriter, plainMessageMetadata, signKeyRing, true, signingContext, ) } func encryptStream( encryptionKeyRing *KeyRing, keyPacketWriter Writer, dataPacketWriter Writer, plainMessageMetadata *PlainMessageMetadata, signKeyRing *KeyRing, compress bool, signingContext *SigningContext, ) (plainMessageWriter WriteCloser, err error) { if plainMessageMetadata == nil { // Use sensible default metadata plainMessageMetadata = &PlainMessageMetadata{ IsBinary: true, Filename: "", ModTime: GetUnixTime(), } } hints := &openpgp.FileHints{ FileName: plainMessageMetadata.Filename, IsBinary: plainMessageMetadata.IsBinary, ModTime: time.Unix(plainMessageMetadata.ModTime, 0), } plainMessageWriter, err = asymmetricEncryptStream(hints, keyPacketWriter, dataPacketWriter, encryptionKeyRing, signKeyRing, compress, signingContext) if err != nil { return nil, err } return plainMessageWriter, nil } // EncryptSplitResult is used to wrap the encryption writecloser while storing the key packet. type EncryptSplitResult struct { isClosed bool keyPacketBuf *bytes.Buffer keyPacket []byte plainMessageWriter WriteCloser // The writer to writer plaintext data in. } func (res *EncryptSplitResult) Write(b []byte) (n int, err error) { return res.plainMessageWriter.Write(b) } func (res *EncryptSplitResult) Close() (err error) { err = res.plainMessageWriter.Close() if err != nil { return err } res.isClosed = true res.keyPacket = res.keyPacketBuf.Bytes() return nil } // GetKeyPacket returns the Public-Key Encrypted Session Key Packets (https://datatracker.ietf.org/doc/html/rfc4880#section-5.1). // This can be retrieved only after the message has been fully written and the writer is closed. func (res *EncryptSplitResult) GetKeyPacket() (keyPacket []byte, err error) { if !res.isClosed { return nil, errors.New("gopenpgp: can't access key packet until the message writer has been closed") } return res.keyPacket, nil } // EncryptSplitStream is used to encrypt data as a stream. // It takes a writer for the Symmetrically Encrypted Data Packet // (https://datatracker.ietf.org/doc/html/rfc4880#section-5.7) // and returns a writer for the plaintext data and the key packet. // If signKeyRing is not nil, it is used to do an embedded signature. func (keyRing *KeyRing) EncryptSplitStream( dataPacketWriter Writer, plainMessageMetadata *PlainMessageMetadata, signKeyRing *KeyRing, ) (*EncryptSplitResult, error) { return encryptSplitStream( keyRing, dataPacketWriter, plainMessageMetadata, signKeyRing, false, nil, ) } // EncryptSplitStreamWithContext is used to encrypt data as a stream. // It takes a writer for the Symmetrically Encrypted Data Packet // (https://datatracker.ietf.org/doc/html/rfc4880#section-5.7) // and returns a writer for the plaintext data and the key packet. // If signKeyRing is not nil, it is used to do an embedded signature. // * signingContext : (optional) a context for the embedded signature. func (keyRing *KeyRing) EncryptSplitStreamWithContext( dataPacketWriter Writer, plainMessageMetadata *PlainMessageMetadata, signKeyRing *KeyRing, signingContext *SigningContext, ) (*EncryptSplitResult, error) { return encryptSplitStream( keyRing, dataPacketWriter, plainMessageMetadata, signKeyRing, false, signingContext, ) } // EncryptSplitStreamWithCompression is used to encrypt data as a stream. // It takes a writer for the Symmetrically Encrypted Data Packet // (https://datatracker.ietf.org/doc/html/rfc4880#section-5.7) // and returns a writer for the plaintext data and the key packet. // If signKeyRing is not nil, it is used to do an embedded signature. func (keyRing *KeyRing) EncryptSplitStreamWithCompression( dataPacketWriter Writer, plainMessageMetadata *PlainMessageMetadata, signKeyRing *KeyRing, ) (*EncryptSplitResult, error) { return encryptSplitStream( keyRing, dataPacketWriter, plainMessageMetadata, signKeyRing, true, nil, ) } // EncryptSplitStreamWithContextAndCompression is used to encrypt data as a stream. // It takes a writer for the Symmetrically Encrypted Data Packet // (https://datatracker.ietf.org/doc/html/rfc4880#section-5.7) // and returns a writer for the plaintext data and the key packet. // If signKeyRing is not nil, it is used to do an embedded signature. // * signingContext : (optional) a context for the embedded signature. func (keyRing *KeyRing) EncryptSplitStreamWithContextAndCompression( dataPacketWriter Writer, plainMessageMetadata *PlainMessageMetadata, signKeyRing *KeyRing, signingContext *SigningContext, ) (*EncryptSplitResult, error) { return encryptSplitStream( keyRing, dataPacketWriter, plainMessageMetadata, signKeyRing, true, signingContext, ) } func encryptSplitStream( encryptionKeyRing *KeyRing, dataPacketWriter Writer, plainMessageMetadata *PlainMessageMetadata, signKeyRing *KeyRing, compress bool, signingContext *SigningContext, ) (*EncryptSplitResult, error) { var keyPacketBuf bytes.Buffer plainMessageWriter, err := encryptStream( encryptionKeyRing, &keyPacketBuf, dataPacketWriter, plainMessageMetadata, signKeyRing, compress, signingContext, ) if err != nil { return nil, err } return &EncryptSplitResult{ keyPacketBuf: &keyPacketBuf, plainMessageWriter: plainMessageWriter, }, nil } // PlainMessageReader is used to wrap the data of the decrypted plain message. // It can be used to read the decrypted data and verify the embedded signature. type PlainMessageReader struct { details *openpgp.MessageDetails verifyKeyRing *KeyRing verifyTime int64 readAll bool verificationContext *VerificationContext } // GetMetadata returns the metadata of the decrypted message. func (msg *PlainMessageReader) GetMetadata() *PlainMessageMetadata { return &PlainMessageMetadata{ Filename: msg.details.LiteralData.FileName, IsBinary: msg.details.LiteralData.IsBinary, ModTime: int64(msg.details.LiteralData.Time), } } // Read is used to access the message decrypted data. // Makes PlainMessageReader implement the Reader interface. func (msg *PlainMessageReader) Read(b []byte) (n int, err error) { n, err = msg.details.UnverifiedBody.Read(b) if errors.Is(err, io.EOF) { msg.readAll = true } return } // VerifySignature is used to verify that the signature is valid. // This method needs to be called once all the data has been read. // It will return an error if the signature is invalid // or if the message hasn't been read entirely. func (msg *PlainMessageReader) VerifySignature() (err error) { if !msg.readAll { return errors.New("gopenpgp: can't verify the signature until the message reader has been read entirely") } if msg.verifyKeyRing != nil { processSignatureExpiration(msg.details, msg.verifyTime) err = verifyDetailsSignature(msg.details, msg.verifyKeyRing, msg.verificationContext) } else { err = errors.New("gopenpgp: no verify keyring was provided before decryption") } return } // DecryptStream is used to decrypt a pgp message as a Reader. // It takes a reader for the message data // and returns a PlainMessageReader for the plaintext data. // If verifyKeyRing is not nil, PlainMessageReader.VerifySignature() will // verify the embedded signature with the given key ring and verification time. func (keyRing *KeyRing) DecryptStream( message Reader, verifyKeyRing *KeyRing, verifyTime int64, ) (plainMessage *PlainMessageReader, err error) { return decryptStream( keyRing, message, verifyKeyRing, verifyTime, nil, ) } // DecryptStreamWithContext is used to decrypt a pgp message as a Reader. // It takes a reader for the message data // and returns a PlainMessageReader for the plaintext data. // If verifyKeyRing is not nil, PlainMessageReader.VerifySignature() will // verify the embedded signature with the given key ring and verification time. // * verificationContext (optional): context for the signature verification. func (keyRing *KeyRing) DecryptStreamWithContext( message Reader, verifyKeyRing *KeyRing, verifyTime int64, verificationContext *VerificationContext, ) (plainMessage *PlainMessageReader, err error) { return decryptStream( keyRing, message, verifyKeyRing, verifyTime, verificationContext, ) } func decryptStream( decryptionKeyRing *KeyRing, message Reader, verifyKeyRing *KeyRing, verifyTime int64, verificationContext *VerificationContext, ) (plainMessage *PlainMessageReader, err error) { messageDetails, err := asymmetricDecryptStream( message, decryptionKeyRing, verifyKeyRing, verifyTime, verificationContext, ) if err != nil { return nil, err } return &PlainMessageReader{ messageDetails, verifyKeyRing, verifyTime, false, verificationContext, }, err } // DecryptSplitStream is used to decrypt a split pgp message as a Reader. // It takes a key packet and a reader for the data packet // and returns a PlainMessageReader for the plaintext data. // If verifyKeyRing is not nil, PlainMessageReader.VerifySignature() will // verify the embedded signature with the given key ring and verification time. func (keyRing *KeyRing) DecryptSplitStream( keypacket []byte, dataPacketReader Reader, verifyKeyRing *KeyRing, verifyTime int64, ) (plainMessage *PlainMessageReader, err error) { messageReader := io.MultiReader( bytes.NewReader(keypacket), dataPacketReader, ) return keyRing.DecryptStream( messageReader, verifyKeyRing, verifyTime, ) } // DecryptSplitStreamWithContext is used to decrypt a split pgp message as a Reader. // It takes a key packet and a reader for the data packet // and returns a PlainMessageReader for the plaintext data. // If verifyKeyRing is not nil, PlainMessageReader.VerifySignature() will // verify the embedded signature with the given key ring and verification time. // * verificationContext (optional): context for the signature verification. func (keyRing *KeyRing) DecryptSplitStreamWithContext( keypacket []byte, dataPacketReader Reader, verifyKeyRing *KeyRing, verifyTime int64, verificationContext *VerificationContext, ) (plainMessage *PlainMessageReader, err error) { messageReader := io.MultiReader( bytes.NewReader(keypacket), dataPacketReader, ) return keyRing.DecryptStreamWithContext( messageReader, verifyKeyRing, verifyTime, verificationContext, ) } // SignDetachedStream generates and returns a PGPSignature for a given message Reader. func (keyRing *KeyRing) SignDetachedStream(message Reader) (*PGPSignature, error) { return keyRing.SignDetachedStreamWithContext(message, nil) } // SignDetachedStreamWithContext generates and returns a PGPSignature for a given message Reader. // If a context is provided, it is added to the signature as notation data // with the name set in `constants.SignatureContextName`. func (keyRing *KeyRing) SignDetachedStreamWithContext(message Reader, context *SigningContext) (*PGPSignature, error) { return signMessageDetached( keyRing, message, true, context, ) } // VerifyDetachedStream verifies a message reader with a detached PGPSignature // and returns a SignatureVerificationError if fails. func (keyRing *KeyRing) VerifyDetachedStream( message Reader, signature *PGPSignature, verifyTime int64, ) error { _, err := verifySignature( keyRing.entities, message, signature.GetBinary(), verifyTime, nil, ) return err } // VerifyDetachedStreamWithContext verifies a message reader with a detached PGPSignature // and returns a SignatureVerificationError if fails. // If a context is provided, it verifies that the signature is valid in the given context, using // the signature notations. func (keyRing *KeyRing) VerifyDetachedStreamWithContext( message Reader, signature *PGPSignature, verifyTime int64, verificationContext *VerificationContext, ) error { _, err := verifySignature( keyRing.entities, message, signature.GetBinary(), verifyTime, verificationContext, ) return err } // SignDetachedEncryptedStream generates and returns a PGPMessage // containing an encrypted detached signature for a given message Reader. func (keyRing *KeyRing) SignDetachedEncryptedStream( message Reader, encryptionKeyRing *KeyRing, ) (encryptedSignature *PGPMessage, err error) { if encryptionKeyRing == nil { return nil, errors.New("gopenpgp: no encryption key ring provided") } signature, err := keyRing.SignDetachedStream(message) if err != nil { return nil, err } plainMessage := NewPlainMessage(signature.GetBinary()) encryptedSignature, err = encryptionKeyRing.Encrypt(plainMessage, nil) return } // VerifyDetachedEncryptedStream verifies a PlainMessage // with a PGPMessage containing an encrypted detached signature // and returns a SignatureVerificationError if fails. func (keyRing *KeyRing) VerifyDetachedEncryptedStream( message Reader, encryptedSignature *PGPMessage, decryptionKeyRing *KeyRing, verifyTime int64, ) error { if decryptionKeyRing == nil { return errors.New("gopenpgp: no decryption key ring provided") } plainMessage, err := decryptionKeyRing.Decrypt(encryptedSignature, nil, 0) if err != nil { return err } signature := NewPGPSignature(plainMessage.GetBinary()) return keyRing.VerifyDetachedStream(message, signature, verifyTime) } golang-github-protonmail-gopenpgp-2.8.1/crypto/keyring_streaming_test.go000066400000000000000000000637051472137343600267240ustar00rootroot00000000000000package crypto import ( "bytes" "io" "io/ioutil" "reflect" "testing" "github.com/pkg/errors" ) const testContext = "test-context" var testMeta = &PlainMessageMetadata{ IsBinary: true, Filename: "filename.txt", ModTime: GetUnixTime(), } func TestKeyRing_EncryptDecryptStream(t *testing.T) { messageBytes := []byte("Hello World!") messageReader := bytes.NewReader(messageBytes) var ciphertextBuf bytes.Buffer messageWriter, err := keyRingTestPublic.EncryptStream( &ciphertextBuf, testMeta, keyRingTestPrivate, ) if err != nil { t.Fatal("Expected no error while encrypting stream with key ring, got:", err) } reachedEnd := false bufferSize := 2 buffer := make([]byte, bufferSize) for !reachedEnd { n, err := messageReader.Read(buffer) if err != nil { if errors.Is(err, io.EOF) { reachedEnd = true } else { t.Fatal("Expected no error while reading data, got:", err) } } writtenTotal := 0 for writtenTotal < n { written, err := messageWriter.Write(buffer[writtenTotal:n]) if err != nil { t.Fatal("Expected no error while writing data, got:", err) } writtenTotal += written } } err = messageWriter.Close() if err != nil { t.Fatal("Expected no error while closing plaintext writer, got:", err) } ciphertextBytes := ciphertextBuf.Bytes() decryptedReader, err := keyRingTestPrivate.DecryptStream( bytes.NewReader(ciphertextBytes), keyRingTestPublic, GetUnixTime(), ) 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 := ioutil.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)) } err = decryptedReader.VerifySignature() if err != nil { t.Fatal("Expected no error while verifying the signature, got:", err) } decryptedMeta := decryptedReader.GetMetadata() if !reflect.DeepEqual(testMeta, decryptedMeta) { t.Fatalf("Expected the decrypted metadata to be %v got %v", testMeta, decryptedMeta) } decryptedReaderNoVerify, err := keyRingTestPrivate.DecryptStream( bytes.NewReader(ciphertextBytes), nil, 0, ) if err != nil { t.Fatal("Expected no error while calling decrypting stream with key ring, got:", err) } decryptedBytes, err = ioutil.ReadAll(decryptedReaderNoVerify) 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)) } decryptedMeta = decryptedReaderNoVerify.GetMetadata() if !reflect.DeepEqual(testMeta, decryptedMeta) { t.Fatalf("Expected the decrypted metadata to be %v got %v", testMeta, decryptedMeta) } err = decryptedReaderNoVerify.VerifySignature() if err == nil { t.Fatal("Expected an error while verifying the signature with no keyring, got nil") } } func TestKeyRing_EncryptDecryptStreamWithContext(t *testing.T) { messageBytes := []byte("Hello World!") messageReader := bytes.NewReader(messageBytes) var ciphertextBuf bytes.Buffer messageWriter, err := keyRingTestPublic.EncryptStreamWithContext( &ciphertextBuf, testMeta, keyRingTestPrivate, NewSigningContext(testContext, true), ) if err != nil { t.Fatal("Expected no error while encrypting stream with key ring, got:", err) } reachedEnd := false bufferSize := 2 buffer := make([]byte, bufferSize) for !reachedEnd { n, err := messageReader.Read(buffer) if err != nil { if errors.Is(err, io.EOF) { reachedEnd = true } else { t.Fatal("Expected no error while reading data, got:", err) } } writtenTotal := 0 for writtenTotal < n { written, err := messageWriter.Write(buffer[writtenTotal:n]) if err != nil { t.Fatal("Expected no error while writing data, got:", err) } writtenTotal += written } } err = messageWriter.Close() if err != nil { t.Fatal("Expected no error while closing plaintext writer, got:", err) } ciphertextBytes := ciphertextBuf.Bytes() decryptedReader, err := keyRingTestPrivate.DecryptStreamWithContext( bytes.NewReader(ciphertextBytes), keyRingTestPublic, GetUnixTime(), NewVerificationContext(testContext, true, 0), ) 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 := ioutil.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)) } err = decryptedReader.VerifySignature() if err != nil { t.Fatal("Expected no error while verifying the signature, got:", err) } decryptedMeta := decryptedReader.GetMetadata() if !reflect.DeepEqual(testMeta, decryptedMeta) { t.Fatalf("Expected the decrypted metadata to be %v got %v", testMeta, decryptedMeta) } decryptedReaderNoVerify, err := keyRingTestPrivate.DecryptStream( bytes.NewReader(ciphertextBytes), nil, 0, ) if err != nil { t.Fatal("Expected no error while calling decrypting stream with key ring, got:", err) } decryptedBytes, err = ioutil.ReadAll(decryptedReaderNoVerify) 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)) } decryptedMeta = decryptedReaderNoVerify.GetMetadata() if !reflect.DeepEqual(testMeta, decryptedMeta) { t.Fatalf("Expected the decrypted metadata to be %v got %v", testMeta, decryptedMeta) } err = decryptedReaderNoVerify.VerifySignature() if err == nil { t.Fatal("Expected an error while verifying the signature with no keyring, got nil") } } func TestKeyRing_EncryptDecryptStreamWithContextAndCompression(t *testing.T) { messageBytes := []byte("Hello World!") messageReader := bytes.NewReader(messageBytes) var ciphertextBuf bytes.Buffer messageWriter, err := keyRingTestPublic.EncryptStreamWithContextAndCompression( &ciphertextBuf, testMeta, keyRingTestPrivate, NewSigningContext(testContext, true), ) if err != nil { t.Fatal("Expected no error while encrypting stream with key ring, got:", err) } reachedEnd := false bufferSize := 2 buffer := make([]byte, bufferSize) for !reachedEnd { n, err := messageReader.Read(buffer) if err != nil { if errors.Is(err, io.EOF) { reachedEnd = true } else { t.Fatal("Expected no error while reading data, got:", err) } } writtenTotal := 0 for writtenTotal < n { written, err := messageWriter.Write(buffer[writtenTotal:n]) if err != nil { t.Fatal("Expected no error while writing data, got:", err) } writtenTotal += written } } err = messageWriter.Close() if err != nil { t.Fatal("Expected no error while closing plaintext writer, got:", err) } ciphertextBytes := ciphertextBuf.Bytes() decryptedReader, err := keyRingTestPrivate.DecryptStreamWithContext( bytes.NewReader(ciphertextBytes), keyRingTestPublic, GetUnixTime(), NewVerificationContext(testContext, true, 0), ) 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 := ioutil.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)) } err = decryptedReader.VerifySignature() if err != nil { t.Fatal("Expected no error while verifying the signature, got:", err) } decryptedMeta := decryptedReader.GetMetadata() if !reflect.DeepEqual(testMeta, decryptedMeta) { t.Fatalf("Expected the decrypted metadata to be %v got %v", testMeta, decryptedMeta) } decryptedReaderNoVerify, err := keyRingTestPrivate.DecryptStream( bytes.NewReader(ciphertextBytes), nil, 0, ) if err != nil { t.Fatal("Expected no error while calling decrypting stream with key ring, got:", err) } decryptedBytes, err = ioutil.ReadAll(decryptedReaderNoVerify) 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)) } decryptedMeta = decryptedReaderNoVerify.GetMetadata() if !reflect.DeepEqual(testMeta, decryptedMeta) { t.Fatalf("Expected the decrypted metadata to be %v got %v", testMeta, decryptedMeta) } err = decryptedReaderNoVerify.VerifySignature() if err == nil { t.Fatal("Expected an error while verifying the signature with no keyring, got nil") } } func TestKeyRing_EncryptStreamCompatible(t *testing.T) { enc := func(w io.Writer, meta *PlainMessageMetadata, kr *KeyRing) (io.WriteCloser, error) { return keyRingTestPublic.EncryptStream( w, meta, kr, ) } testKeyRing_EncryptStreamCompatible(enc, t) } func TestKeyRing_EncryptStreamWithCompressionCompatible(t *testing.T) { enc := func(w io.Writer, meta *PlainMessageMetadata, kr *KeyRing) (io.WriteCloser, error) { return keyRingTestPublic.EncryptStreamWithCompression( w, meta, kr, ) } testKeyRing_EncryptStreamCompatible(enc, t) } type keyringEncryptionFunction = func(io.Writer, *PlainMessageMetadata, *KeyRing) (io.WriteCloser, error) func testKeyRing_EncryptStreamCompatible(encrypt keyringEncryptionFunction, t *testing.T) { messageBytes := []byte("Hello World!") messageReader := bytes.NewReader(messageBytes) var ciphertextBuf bytes.Buffer messageWriter, err := encrypt( &ciphertextBuf, testMeta, keyRingTestPrivate, ) if err != nil { t.Fatal("Expected no error while encrypting stream with key ring, got:", err) } reachedEnd := false bufferSize := 2 buffer := make([]byte, bufferSize) for !reachedEnd { n, err := messageReader.Read(buffer) if err != nil { if errors.Is(err, io.EOF) { reachedEnd = true } else { t.Fatal("Expected no error while reading data, got:", err) } } writtenTotal := 0 for writtenTotal < n { written, err := messageWriter.Write(buffer[writtenTotal:n]) if err != nil { t.Fatal("Expected no error while writing data, got:", err) } writtenTotal += written } } err = messageWriter.Close() if err != nil { t.Fatal("Expected no error while closing plaintext writer, got:", err) } encryptedData := ciphertextBuf.Bytes() decryptedMsg, err := keyRingTestPrivate.Decrypt( NewPGPMessage(encryptedData), keyRingTestPublic, GetUnixTime(), ) if err != nil { t.Fatal("Expected no error while calling normal decrypt with key ring, got:", err) } decryptedBytes := decryptedMsg.GetBinary() if !bytes.Equal(decryptedBytes, messageBytes) { t.Fatalf("Expected the normally decrypted data to be %s got %s", string(decryptedBytes), string(messageBytes)) } if testMeta.IsBinary != decryptedMsg.IsBinary() { t.Fatalf("Expected isBinary to be %t got %t", testMeta.IsBinary, decryptedMsg.IsBinary()) } if testMeta.Filename != decryptedMsg.GetFilename() { t.Fatalf("Expected filename to be %s got %s", testMeta.Filename, decryptedMsg.GetFilename()) } if testMeta.ModTime != int64(decryptedMsg.GetTime()) { t.Fatalf("Expected modification time to be %d got %d", testMeta.ModTime, int64(decryptedMsg.GetTime())) } } func TestKeyRing_DecryptStreamCompatible(t *testing.T) { messageBytes := []byte("Hello World!") pgpMessage, err := keyRingTestPublic.Encrypt( &PlainMessage{ Data: messageBytes, TextType: !testMeta.IsBinary, Time: uint32(testMeta.ModTime), Filename: testMeta.Filename, }, keyRingTestPrivate, ) if err != nil { t.Fatal("Expected no error while encrypting plaintext, got:", err) } decryptedReader, err := keyRingTestPrivate.DecryptStream( bytes.NewReader(pgpMessage.GetBinary()), keyRingTestPublic, GetUnixTime(), ) if err != nil { t.Fatal("Expected no error while calling decrypting stream with key ring, got:", err) } decryptedBytes, err := ioutil.ReadAll(decryptedReader) if err != nil { t.Fatal("Expected no error while reading the decrypted data, got:", err) } err = decryptedReader.VerifySignature() if err != nil { t.Fatal("Expected no error while verifying the signature, got:", err) } if !bytes.Equal(decryptedBytes, messageBytes) { t.Fatalf("Expected the decrypted data to be %s got %s", string(decryptedBytes), string(messageBytes)) } decryptedMeta := decryptedReader.GetMetadata() if !reflect.DeepEqual(testMeta, decryptedMeta) { t.Fatalf("Expected the decrypted metadata to be %v got %v", testMeta, decryptedMeta) } } func TestKeyRing_EncryptDecryptSplitStream(t *testing.T) { messageBytes := []byte("Hello World!") messageReader := bytes.NewReader(messageBytes) var dataPacketBuf bytes.Buffer encryptionResult, err := keyRingTestPublic.EncryptSplitStream( &dataPacketBuf, testMeta, keyRingTestPrivate, ) if err != nil { t.Fatal("Expected no error while calling encrypting split stream with key ring, got:", err) } messageWriter := encryptionResult reachedEnd := false bufferSize := 2 buffer := make([]byte, bufferSize) for !reachedEnd { n, err := messageReader.Read(buffer) if err != nil { if errors.Is(err, io.EOF) { reachedEnd = true } else { t.Fatal("Expected no error while reading data, got:", err) } } writtenTotal := 0 for writtenTotal < n { written, err := messageWriter.Write(buffer[writtenTotal:n]) if err != nil { t.Fatal("Expected no error while writing data, got:", err) } writtenTotal += written } } err = messageWriter.Close() if err != nil { t.Fatal("Expected no error while closing plaintext writer, got:", err) } keyPacket, err := encryptionResult.GetKeyPacket() if err != nil { t.Fatal("Expected no error while accessing key packet, got:", err) } dataPacket := dataPacketBuf.Bytes() decryptedReader, err := keyRingTestPrivate.DecryptSplitStream( keyPacket, bytes.NewReader(dataPacket), keyRingTestPublic, GetUnixTime(), ) if err != nil { t.Fatal("Expected no error while decrypting split stream with key ring, got:", err) } decryptedBytes, err := ioutil.ReadAll(decryptedReader) if err != nil { t.Fatal("Expected no error while reading the decrypted data, got:", err) } err = decryptedReader.VerifySignature() if err != nil { t.Fatal("Expected no error while verifying the signature, got:", err) } if !bytes.Equal(decryptedBytes, messageBytes) { t.Fatalf("Expected the decrypted data to be %s got %s", string(decryptedBytes), string(messageBytes)) } decryptedMeta := decryptedReader.GetMetadata() if !reflect.DeepEqual(testMeta, decryptedMeta) { t.Fatalf("Expected the decrypted metadata to be %v got %v", testMeta, decryptedMeta) } } func TestKeyRing_EncryptDecryptSplitStreamWithCont(t *testing.T) { messageBytes := []byte("Hello World!") messageReader := bytes.NewReader(messageBytes) var dataPacketBuf bytes.Buffer encryptionResult, err := keyRingTestPublic.EncryptSplitStreamWithContext( &dataPacketBuf, testMeta, keyRingTestPrivate, NewSigningContext(testContext, true), ) if err != nil { t.Fatal("Expected no error while calling encrypting split stream with key ring, got:", err) } messageWriter := encryptionResult _, err = io.Copy(messageWriter, messageReader) if err != nil { t.Fatal("Expected no error while copying plaintext writer, got:", err) } err = messageWriter.Close() if err != nil { t.Fatal("Expected no error while closing plaintext writer, got:", err) } keyPacket, err := encryptionResult.GetKeyPacket() if err != nil { t.Fatal("Expected no error while accessing key packet, got:", err) } dataPacket := dataPacketBuf.Bytes() decryptedReader, err := keyRingTestPrivate.DecryptSplitStreamWithContext( keyPacket, bytes.NewReader(dataPacket), keyRingTestPublic, GetUnixTime(), NewVerificationContext(testContext, true, 0), ) if err != nil { t.Fatal("Expected no error while decrypting split stream with key ring, got:", err) } decryptedBytes, err := ioutil.ReadAll(decryptedReader) if err != nil { t.Fatal("Expected no error while reading the decrypted data, got:", err) } err = decryptedReader.VerifySignature() if err != nil { t.Fatal("Expected no error while verifying the signature, got:", err) } if !bytes.Equal(decryptedBytes, messageBytes) { t.Fatalf("Expected the decrypted data to be %s got %s", string(decryptedBytes), string(messageBytes)) } } func TestKeyRing_EncryptSplitStreamCompatible(t *testing.T) { enc := func(w io.Writer, meta *PlainMessageMetadata, kr *KeyRing) (*EncryptSplitResult, error) { return keyRingTestPublic.EncryptSplitStream( w, meta, kr, ) } testKeyRing_EncryptSplitStreamCompatible(enc, t) } func TestKeyRing_EncryptSplitStreamWithCompressionCompatible(t *testing.T) { enc := func(w io.Writer, meta *PlainMessageMetadata, kr *KeyRing) (*EncryptSplitResult, error) { return keyRingTestPublic.EncryptSplitStreamWithCompression( w, meta, kr, ) } testKeyRing_EncryptSplitStreamCompatible(enc, t) } type keyringEncryptionSplitFunction = func(io.Writer, *PlainMessageMetadata, *KeyRing) (*EncryptSplitResult, error) func testKeyRing_EncryptSplitStreamCompatible(encrypt keyringEncryptionSplitFunction, t *testing.T) { messageBytes := []byte("Hello World!") messageReader := bytes.NewReader(messageBytes) var dataPacketBuf bytes.Buffer encryptionResult, err := encrypt( &dataPacketBuf, testMeta, keyRingTestPrivate, ) if err != nil { t.Fatal("Expected no error while calling encrypting split stream with key ring, got:", err) } messageWriter := encryptionResult reachedEnd := false bufferSize := 2 buffer := make([]byte, bufferSize) for !reachedEnd { n, err := messageReader.Read(buffer) if err != nil { if errors.Is(err, io.EOF) { reachedEnd = true } else { t.Fatal("Expected no error while reading data, got:", err) } } writtenTotal := 0 for writtenTotal < n { written, err := messageWriter.Write(buffer[writtenTotal:n]) if err != nil { t.Fatal("Expected no error while writing data, got:", err) } writtenTotal += written } } err = messageWriter.Close() if err != nil { t.Fatal("Expected no error while closing plaintext writer, got:", err) } keyPacket, err := encryptionResult.GetKeyPacket() if err != nil { t.Fatal("Expected no error while accessing key packet, got:", err) } dataPacket := dataPacketBuf.Bytes() decryptedMsg, err := keyRingTestPrivate.Decrypt( NewPGPSplitMessage(keyPacket, dataPacket).GetPGPMessage(), keyRingTestPublic, GetUnixTime(), ) if err != nil { t.Fatal("Expected no error while decrypting split stream with key ring, got:", err) } decryptedBytes := decryptedMsg.GetBinary() 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 testMeta.IsBinary != decryptedMsg.IsBinary() { t.Fatalf("Expected isBinary to be %t got %t", testMeta.IsBinary, decryptedMsg.IsBinary()) } if testMeta.Filename != decryptedMsg.GetFilename() { t.Fatalf("Expected filename to be %s got %s", testMeta.Filename, decryptedMsg.GetFilename()) } if testMeta.ModTime != int64(decryptedMsg.GetTime()) { t.Fatalf("Expected modification time to be %d got %d", testMeta.ModTime, int64(decryptedMsg.GetTime())) } } func TestKeyRing_DecryptSplitStreamCompatible(t *testing.T) { messageBytes := []byte("Hello World!") pgpMessage, err := keyRingTestPublic.Encrypt( &PlainMessage{ Data: messageBytes, TextType: !testMeta.IsBinary, Time: uint32(testMeta.ModTime), Filename: testMeta.Filename, }, keyRingTestPrivate, ) if err != nil { t.Fatal("Expected no error while encrypting plaintext, got:", err) } armored, err := pgpMessage.GetArmored() if err != nil { t.Fatal("Expected no error while armoring ciphertext, got:", err) } splitMsg, err := NewPGPSplitMessageFromArmored(armored) if err != nil { t.Fatal("Expected no error while splitting the ciphertext, got:", err) } keyPacket := splitMsg.KeyPacket if err != nil { t.Fatal("Expected no error while accessing key packet, got:", err) } dataPacket := splitMsg.DataPacket decryptedReader, err := keyRingTestPrivate.DecryptSplitStream( keyPacket, bytes.NewReader(dataPacket), keyRingTestPublic, GetUnixTime(), ) if err != nil { t.Fatal("Expected no error while decrypting split stream with key ring, got:", err) } decryptedBytes, err := ioutil.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)) } err = decryptedReader.VerifySignature() if err != nil { t.Fatal("Expected no error while verifying the signature, got:", err) } decryptedMeta := decryptedReader.GetMetadata() if !reflect.DeepEqual(testMeta, decryptedMeta) { t.Fatalf("Expected the decrypted metadata to be %v got %v", testMeta, decryptedMeta) } } func TestKeyRing_SignVerifyDetachedStream(t *testing.T) { messageBytes := []byte("Hello World!") messageReader := bytes.NewReader(messageBytes) signature, err := keyRingTestPrivate.SignDetachedStream(messageReader) if err != nil { t.Fatal("Expected no error while signing the message, got:", err) } _, err = messageReader.Seek(0, 0) if err != nil { t.Fatal("Expected no error while rewinding the message reader, got:", err) } err = keyRingTestPublic.VerifyDetachedStream(messageReader, signature, GetUnixTime()) if err != nil { t.Fatal("Expected no error while verifying the detached signature, got:", err) } } func TestKeyRing_SignVerifyDetachedStreamWithContext(t *testing.T) { messageBytes := []byte("Hello World!") messageReader := bytes.NewReader(messageBytes) signature, err := keyRingTestPrivate.SignDetachedStreamWithContext(messageReader, NewSigningContext(testContext, true)) if err != nil { t.Fatal("Expected no error while signing the message, got:", err) } _, err = messageReader.Seek(0, 0) if err != nil { t.Fatal("Expected no error while rewinding the message reader, got:", err) } err = keyRingTestPublic.VerifyDetachedStreamWithContext(messageReader, signature, GetUnixTime(), NewVerificationContext(testContext, true, 0)) if err != nil { t.Fatal("Expected no error while verifying the detached signature, got:", err) } } func TestKeyRing_SignDetachedStreamCompatible(t *testing.T) { messageBytes := []byte("Hello World!") messageReader := bytes.NewReader(messageBytes) signature, err := keyRingTestPrivate.SignDetachedStream(messageReader) if err != nil { t.Fatal("Expected no error while signing the message, got:", err) } err = keyRingTestPublic.VerifyDetached(NewPlainMessage(messageBytes), signature, GetUnixTime()) if err != nil { t.Fatal("Expected no error while verifying the detached signature, got:", err) } } func TestKeyRing_VerifyDetachedStreamCompatible(t *testing.T) { messageBytes := []byte("Hello World!") messageReader := bytes.NewReader(messageBytes) signature, err := keyRingTestPrivate.SignDetached(NewPlainMessage(messageBytes)) if err != nil { t.Fatal("Expected no error while signing the message, got:", err) } _, err = messageReader.Seek(0, 0) if err != nil { t.Fatal("Expected no error while rewinding the message reader, got:", err) } err = keyRingTestPublic.VerifyDetachedStream(messageReader, signature, GetUnixTime()) if err != nil { t.Fatal("Expected no error while verifying the detached signature, got:", err) } } func TestKeyRing_SignVerifyDetachedEncryptedStream(t *testing.T) { messageBytes := []byte("Hello World!") messageReader := bytes.NewReader(messageBytes) encSignature, err := keyRingTestPrivate.SignDetachedEncryptedStream(messageReader, keyRingTestPublic) if err != nil { t.Fatal("Expected no error while signing the message, got:", err) } _, err = messageReader.Seek(0, 0) if err != nil { t.Fatal("Expected no error while rewinding the message reader, got:", err) } err = keyRingTestPublic.VerifyDetachedEncryptedStream(messageReader, encSignature, keyRingTestPrivate, GetUnixTime()) if err != nil { t.Fatal("Expected no error while verifying the detached signature, got:", err) } } func TestKeyRing_SignDetachedEncryptedStreamCompatible(t *testing.T) { messageBytes := []byte("Hello World!") messageReader := bytes.NewReader(messageBytes) encSignature, err := keyRingTestPrivate.SignDetachedEncryptedStream(messageReader, keyRingTestPublic) if err != nil { t.Fatal("Expected no error while signing the message, got:", err) } err = keyRingTestPublic.VerifyDetachedEncrypted(NewPlainMessage(messageBytes), encSignature, keyRingTestPrivate, GetUnixTime()) if err != nil { t.Fatal("Expected no error while verifying the detached signature, got:", err) } } func TestKeyRing_VerifyDetachedEncryptedStreamCompatible(t *testing.T) { messageBytes := []byte("Hello World!") messageReader := bytes.NewReader(messageBytes) encSignature, err := keyRingTestPrivate.SignDetachedEncrypted(NewPlainMessage(messageBytes), keyRingTestPublic) if err != nil { t.Fatal("Expected no error while signing the message, got:", err) } _, err = messageReader.Seek(0, 0) if err != nil { t.Fatal("Expected no error while rewinding the message reader, got:", err) } err = keyRingTestPublic.VerifyDetachedEncryptedStream(messageReader, encSignature, keyRingTestPrivate, GetUnixTime()) if err != nil { t.Fatal("Expected no error while verifying the detached signature, got:", err) } } golang-github-protonmail-gopenpgp-2.8.1/crypto/keyring_test.go000066400000000000000000000204551472137343600246460ustar00rootroot00000000000000package crypto import ( "crypto/rsa" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/ProtonMail/go-crypto/openpgp/ecdh" "github.com/ProtonMail/go-crypto/openpgp/eddsa" "github.com/ProtonMail/gopenpgp/v2/constants" ) 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()) 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()) } 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()) } } func TestEncryptedDetachedSignature(t *testing.T) { keyRingPrivate, err := keyRingTestPrivate.Copy() if err != nil { t.Fatal("Expected no error while copying keyring, got:", err) } keyRingPublic, err := keyRingTestPublic.Copy() if err != nil { t.Fatal("Expected no error while copying keyring, got:", err) } message := NewPlainMessageFromString("Hello World!") encSign, err := keyRingPrivate.SignDetachedEncrypted(message, keyRingPublic) if err != nil { t.Fatal("Expected no error while encryptedSigning, got:", err) } err = keyRingPublic.VerifyDetachedEncrypted(message, encSign, keyRingPrivate, 0) if err != nil { t.Fatal("Expected no error while verifying encSignature, got:", err) } message2 := NewPlainMessageFromString("Bye!") err = keyRingPublic.VerifyDetachedEncrypted(message2, encSign, keyRingPrivate, 0) if err == nil { t.Fatal("Expected an error while verifying bad encSignature, got nil") } } func TestKeyringCapabilities(t *testing.T) { assert.True(t, keyRingTestPrivate.CanVerify()) assert.True(t, keyRingTestPrivate.CanEncrypt()) assert.True(t, keyRingTestPublic.CanVerify()) assert.True(t, keyRingTestPublic.CanEncrypt()) assert.True(t, keyRingTestMultiple.CanVerify()) assert.True(t, keyRingTestMultiple.CanEncrypt()) } func TestVerificationTime(t *testing.T) { message := NewPlainMessageFromString("Hello") pgp.latestServerTime = 1632312383 defer func() { pgp.latestServerTime = testTime }() enc, err := keyRingTestPublic.Encrypt( message, keyRingTestPrivate, ) if err != nil { t.Fatalf("Encryption error: %v", err) } _, err = keyRingTestPrivate.Decrypt( enc, keyRingTestPublic, 392039755, ) if err == nil { t.Fatal("No signature error") } castedErr := &SignatureVerificationError{} isType := errors.As(err, castedErr) if !isType { t.Fatalf("No signature error %v", err) } if castedErr.Status != constants.SIGNATURE_FAILED { t.Fatalf("Wrong status %v", castedErr) } _, err = keyRingTestPrivate.Decrypt( enc, keyRingTestPublic, 0, ) if err != nil { t.Fatalf("Got an error while decrypting %v", err) } } golang-github-protonmail-gopenpgp-2.8.1/crypto/message.go000066400000000000000000000361351472137343600235650ustar00rootroot00000000000000package crypto import ( "bytes" "encoding/base64" "encoding/json" goerrors "errors" "io" "io/ioutil" "regexp" "strings" "time" "github.com/ProtonMail/go-crypto/openpgp/clearsign" "github.com/ProtonMail/go-crypto/openpgp/packet" "github.com/ProtonMail/gopenpgp/v2/armor" "github.com/ProtonMail/gopenpgp/v2/constants" "github.com/ProtonMail/gopenpgp/v2/internal" "github.com/pkg/errors" ) // ---- MODELS ----- // 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 // The file's latest modification time Time uint32 // The encrypted message's filename Filename string } // PGPMessage stores a PGP-encrypted message. type PGPMessage struct { // The content of the message Data []byte } // PGPSignature stores a PGP-encoded detached signature. type PGPSignature struct { // The content of the signature Data []byte } // PGPSplitMessage contains a separate session key packet and symmetrically // encrypted data packet. type PGPSplitMessage struct { DataPacket []byte KeyPacket []byte } // A ClearTextMessage is a signed but not encrypted PGP message, // i.e. the ones beginning with -----BEGIN PGP SIGNED MESSAGE-----. type ClearTextMessage struct { Data []byte Signature []byte } // ---- GENERATORS ----- // NewPlainMessage generates a new binary PlainMessage ready for encryption, // signature, or verification from the unencrypted binary data. // This will encrypt the message with the binary flag and preserve the file as is. func NewPlainMessage(data []byte) *PlainMessage { return &PlainMessage{ Data: clone(data), TextType: false, Filename: "", Time: uint32(GetUnixTime()), } } // NewPlainMessageFromFile generates a new binary PlainMessage ready for encryption, // signature, or verification from the unencrypted binary data. // This will encrypt the message with the binary flag and preserve the file as is. // It assigns a filename and a modification time. func NewPlainMessageFromFile(data []byte, filename string, time uint32) *PlainMessage { return &PlainMessage{ Data: clone(data), TextType: false, Filename: filename, Time: time, } } // NewPlainMessageFromString generates a new text PlainMessage, // ready for encryption, signature, or verification from an unencrypted string. // This will encrypt the message with the text flag, canonicalize the line endings // (i.e. set all of them to \r\n) and strip the trailing spaces for each line. // This allows seamless conversion to clear text signed messages (see RFC 4880 5.2.1 and 7.1). func NewPlainMessageFromString(text string) *PlainMessage { return &PlainMessage{ Data: []byte(internal.Canonicalize(text)), TextType: true, Filename: "", Time: uint32(GetUnixTime()), } } // NewPGPMessage generates a new PGPMessage from the unarmored binary data. func NewPGPMessage(data []byte) *PGPMessage { return &PGPMessage{ Data: clone(data), } } // 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 := ioutil.ReadAll(encryptedIO.Body) if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in reading armored message") } return &PGPMessage{ Data: message, }, nil } // NewPGPSplitMessage generates a new PGPSplitMessage from the binary unarmored keypacket, // datapacket, and encryption algorithm. func NewPGPSplitMessage(keyPacket []byte, dataPacket []byte) *PGPSplitMessage { return &PGPSplitMessage{ KeyPacket: clone(keyPacket), DataPacket: clone(dataPacket), } } // NewPGPSplitMessageFromArmored generates a new PGPSplitMessage by splitting an armored message into its // session key packet and symmetrically encrypted data packet. func NewPGPSplitMessageFromArmored(encrypted string) (*PGPSplitMessage, error) { message, err := NewPGPMessageFromArmored(encrypted) if err != nil { return nil, err } return message.SplitMessage() } // NewPGPSignature generates a new PGPSignature from the unarmored binary data. func NewPGPSignature(data []byte) *PGPSignature { return &PGPSignature{ Data: clone(data), } } // NewPGPSignatureFromArmored generates a new PGPSignature from the armored // string ready for verification. func NewPGPSignatureFromArmored(armored string) (*PGPSignature, error) { encryptedIO, err := internal.Unarmor(armored) if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in unarmoring signature") } signature, err := ioutil.ReadAll(encryptedIO.Body) if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in reading armored signature") } return &PGPSignature{ Data: signature, }, nil } // NewClearTextMessage generates a new ClearTextMessage from data and // signature. func NewClearTextMessage(data []byte, signature []byte) *ClearTextMessage { return &ClearTextMessage{ Data: clone(data), Signature: clone(signature), } } // NewClearTextMessageFromArmored returns the message body and unarmored // signature from a clearsigned message. func NewClearTextMessageFromArmored(signedMessage string) (*ClearTextMessage, error) { modulusBlock, rest := clearsign.Decode([]byte(signedMessage)) if len(rest) != 0 { return nil, errors.New("gopenpgp: extra data after modulus") } signature, err := ioutil.ReadAll(modulusBlock.ArmoredSignature.Body) if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in reading cleartext message") } return NewClearTextMessage(modulusBlock.Bytes, signature), nil } // ---- MODEL METHODS ----- // GetBinary returns the binary content of the message as a []byte. func (msg *PlainMessage) GetBinary() []byte { return msg.Data } // GetString returns the content of the message as a string. func (msg *PlainMessage) GetString() string { return sanitizeString(strings.ReplaceAll(string(msg.Data), "\r\n", "\n")) } // GetBase64 returns the base-64 encoded binary content of the message as a // string. func (msg *PlainMessage) GetBase64() string { return base64.StdEncoding.EncodeToString(msg.Data) } // NewReader returns a New io.Reader for the binary data of the message. func (msg *PlainMessage) NewReader() io.Reader { return bytes.NewReader(msg.GetBinary()) } // IsText returns whether the message is a text message. func (msg *PlainMessage) IsText() bool { return msg.TextType } // IsBinary returns whether the message is a binary message. func (msg *PlainMessage) IsBinary() bool { return !msg.TextType } // getFormattedTime returns the message (latest modification) Time as time.Time. func (msg *PlainMessage) getFormattedTime() time.Time { return time.Unix(int64(msg.Time), 0) } // GetBinary returns the unarmored binary content of the message as a []byte. func (msg *PGPMessage) GetBinary() []byte { return msg.Data } // NewReader returns a New io.Reader for the unarmored binary data of the // message. func (msg *PGPMessage) NewReader() io.Reader { return bytes.NewReader(msg.GetBinary()) } // GetArmored returns the armored message as a string. func (msg *PGPMessage) GetArmored() (string, error) { return armor.ArmorWithType(msg.Data, constants.PGPMessageHeader) } // GetArmoredWithCustomHeaders returns the armored message as a string, with // the given headers. Empty parameters are omitted from the headers. func (msg *PGPMessage) GetArmoredWithCustomHeaders(comment, version string) (string, error) { return armor.ArmorWithTypeAndCustomHeaders(msg.Data, constants.PGPMessageHeader, version, comment) } // GetEncryptionKeyIDs Returns the key IDs of the keys to which the session key is encrypted. func (msg *PGPMessage) GetEncryptionKeyIDs() ([]uint64, bool) { packets := packet.NewReader(bytes.NewReader(msg.Data)) 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 } // GetHexEncryptionKeyIDs Returns the key IDs of the keys to which the session key is encrypted. func (msg *PGPMessage) GetHexEncryptionKeyIDs() ([]string, bool) { return getHexKeyIDs(msg.GetEncryptionKeyIDs()) } // GetHexEncryptionKeyIDsJson 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) GetHexEncryptionKeyIDsJson() []byte { hexIds, ok := msg.GetHexEncryptionKeyIDs() if !ok { return nil } hexIdsJson, err := json.Marshal(hexIds) if err != nil { return nil } return hexIdsJson } // GetSignatureKeyIDs Returns the key IDs of the keys to which the (readable) signature packets are encrypted to. func (msg *PGPMessage) GetSignatureKeyIDs() ([]uint64, bool) { return getSignatureKeyIDs(msg.Data) } // GetHexSignatureKeyIDs Returns the key IDs of the keys to which the session key is encrypted. func (msg *PGPMessage) GetHexSignatureKeyIDs() ([]string, bool) { return getHexKeyIDs(msg.GetSignatureKeyIDs()) } // GetHexSignatureKeyIDsJson returns the key IDs of the keys to which the (readable) signature packets // are encrypted to as a JSON array. Helper function for go-mobile clients. func (msg *PGPMessage) GetHexSignatureKeyIDsJson() []byte { sigHexSigIds, ok := msg.GetHexSignatureKeyIDs() if !ok { return nil } sigHexKeyIdsJSON, err := json.Marshal(sigHexSigIds) if err != nil { return nil } return sigHexKeyIdsJSON } // GetBinaryDataPacket returns the unarmored binary datapacket as a []byte. func (msg *PGPSplitMessage) GetBinaryDataPacket() []byte { return msg.DataPacket } // GetBinaryKeyPacket returns the unarmored binary keypacket as a []byte. func (msg *PGPSplitMessage) GetBinaryKeyPacket() []byte { return msg.KeyPacket } // GetBinary returns the unarmored binary joined packets as a []byte. func (msg *PGPSplitMessage) GetBinary() []byte { return append(msg.KeyPacket, msg.DataPacket...) } // GetArmored returns the armored message as a string, with joined data and key // packets. func (msg *PGPSplitMessage) GetArmored() (string, error) { return armor.ArmorWithType(msg.GetBinary(), constants.PGPMessageHeader) } // GetPGPMessage joins asymmetric session key packet with the symmetric data // packet to obtain a PGP message. func (msg *PGPSplitMessage) GetPGPMessage() *PGPMessage { return NewPGPMessage(append(msg.KeyPacket, msg.DataPacket...)) } // GetNumberOfKeyPackets returns the number of keys packets in this message. func (msg *PGPSplitMessage) 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). // Parameters are for backwards compatibility and are unused. func (msg *PGPMessage) SplitMessage() (*PGPSplitMessage, error) { bytesReader := bytes.NewReader(msg.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 &PGPSplitMessage{ KeyPacket: clone(msg.Data[:splitPoint]), DataPacket: clone(msg.Data[splitPoint:]), }, nil } // SeparateKeyAndData splits the message into key and data packet(s). // Parameters are for backwards compatibility and are unused. // Deprecated: use SplitMessage(). func (msg *PGPMessage) SeparateKeyAndData(_ int, _ int) (*PGPSplitMessage, error) { return msg.SplitMessage() } // GetBinary returns the unarmored binary content of the signature as a []byte. func (sig *PGPSignature) GetBinary() []byte { return sig.Data } // GetArmored returns the armored signature as a string. func (sig *PGPSignature) GetArmored() (string, error) { return armor.ArmorWithType(sig.Data, constants.PGPSignatureHeader) } // GetSignatureKeyIDs Returns the key IDs of the keys to which the (readable) signature packets are encrypted to. func (sig *PGPSignature) GetSignatureKeyIDs() ([]uint64, bool) { return getSignatureKeyIDs(sig.Data) } // GetHexSignatureKeyIDs Returns the key IDs of the keys to which the session key is encrypted. func (sig *PGPSignature) GetHexSignatureKeyIDs() ([]string, bool) { return getHexKeyIDs(sig.GetSignatureKeyIDs()) } // GetBinary returns the unarmored signed data as a []byte. func (msg *ClearTextMessage) GetBinary() []byte { return msg.Data } // GetString returns the unarmored signed data as a string. func (msg *ClearTextMessage) GetString() string { return string(msg.Data) } // GetBinarySignature returns the unarmored binary signature as a []byte. func (msg *ClearTextMessage) GetBinarySignature() []byte { return msg.Signature } // GetArmored armors plaintext and signature with the PGP SIGNED MESSAGE // armoring. func (msg *ClearTextMessage) GetArmored() (string, error) { armSignature, err := armor.ArmorWithType(msg.GetBinarySignature(), constants.PGPSignatureHeader) if err != nil { return "", errors.Wrap(err, "gopenpgp: error in armoring cleartext message") } str := "-----BEGIN PGP SIGNED MESSAGE-----\r\nHash: SHA512\r\n\r\n" str += msg.GetString() str += "\r\n" str += armSignature return str, nil } // ---- 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) } func getSignatureKeyIDs(data []byte) ([]uint64, bool) { packets := packet.NewReader(bytes.NewReader(data)) 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 } func getHexKeyIDs(keyIDs []uint64, ok bool) ([]string, bool) { hexIDs := make([]string, len(keyIDs)) for i, id := range keyIDs { hexIDs[i] = keyIDToHex(id) } return hexIDs, ok } golang-github-protonmail-gopenpgp-2.8.1/crypto/message_getters.go000066400000000000000000000005241472137343600253130ustar00rootroot00000000000000//go:build !android // +build !android package crypto // GetFilename returns the file name of the message as a string. func (msg *PlainMessage) GetFilename() string { return msg.Filename } // GetTime returns the modification time of a file (if provided in the ciphertext). func (msg *PlainMessage) GetTime() uint32 { return msg.Time } golang-github-protonmail-gopenpgp-2.8.1/crypto/message_test.go000066400000000000000000000371011472137343600246160ustar00rootroot00000000000000package crypto import ( "bytes" "encoding/base64" "errors" "io" "io/ioutil" "testing" "time" "github.com/ProtonMail/go-crypto/openpgp/packet" "github.com/stretchr/testify/assert" ) func TestTextMessageEncryptionWithPassword(t *testing.T) { var message = NewPlainMessageFromString("The secret code is... 1, 2, 3, 4, 5") // Encrypt data with password encrypted, err := EncryptMessageWithPassword(message, testSymmetricKey) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } packets := packet.NewReader(bytes.NewReader(encrypted.GetBinary())) 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 _, err = DecryptMessageWithPassword(encrypted, []byte("Wrong password")) assert.NotNil(t, err) // Decrypt data with the good password decrypted, err := DecryptMessageWithPassword(encrypted, testSymmetricKey) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, message.GetString(), decrypted.GetString()) } func TestBinaryMessageEncryptionWithPassword(t *testing.T) { binData, _ := base64.StdEncoding.DecodeString("ExXmnSiQ2QCey20YLH6qlLhkY3xnIBC1AwlIXwK/HvY=") var message = NewPlainMessage(binData) // Encrypt data with password encrypted, err := EncryptMessageWithPassword(message, testSymmetricKey) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } // Decrypt data with wrong password _, err = DecryptMessageWithPassword(encrypted, []byte("Wrong password")) assert.NotNil(t, err) // Decrypt data with the good password decrypted, err := DecryptMessageWithPassword(encrypted, testSymmetricKey) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, message, decrypted) } 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 decrypted, err := DecryptMessageWithPassword(encrypted, []byte("pinata")) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } expected, err := ioutil.ReadFile("testdata/message_mixedPasswordPublicExpected") if err != nil { panic(err) } assert.Exactly(t, expected, decrypted.GetBinary()) } func TestTextMessageEncryption(t *testing.T) { var message = NewPlainMessageFromString( "The secret code is... 1, 2, 3, 4, 5. I repeat: the secret code is... 1, 2, 3, 4, 5", ) ciphertext, err := keyRingTestPublic.Encrypt(message, nil) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } split, err := ciphertext.SplitMessage() if err != nil { t.Fatal("Expected no error when splitting, got:", err) } assert.Len(t, split.GetBinaryDataPacket(), 133) // Assert uncompressed encrypted body length decrypted, err := keyRingTestPrivate.Decrypt(ciphertext, nil, 0) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, message.GetString(), decrypted.GetString()) } 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 = NewPlainMessageFromString(original) ciphertext, err := keyRingTestPublic.Encrypt(message, nil) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } decrypted, err := keyRingTestPrivate.Decrypt(ciphertext, nil, 0) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, original, decrypted.GetString()) } 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 = NewPlainMessageFromString(original) ciphertext, err := keyRingTestPublic.Encrypt(message, nil) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } decrypted, err := keyRingTestPrivate.Decrypt(ciphertext, nil, 0) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, original, decrypted.GetString()) } func TestTextMessageEncryptionWithCompression(t *testing.T) { var message = NewPlainMessageFromString( "The secret code is... 1, 2, 3, 4, 5. I repeat: the secret code is... 1, 2, 3, 4, 5", ) ciphertext, err := keyRingTestPublic.EncryptWithCompression(message, nil) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } split, err := ciphertext.SplitMessage() if err != nil { t.Fatal("Expected no error when splitting, got:", err) } assert.Len(t, split.GetBinaryDataPacket(), 117) // Assert uncompressed encrypted body length decrypted, err := keyRingTestPrivate.Decrypt(ciphertext, nil, 0) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, message.GetString(), decrypted.GetString()) } func TestTextMessageEncryptionWithSignature(t *testing.T) { var message = NewPlainMessageFromString("plain text") ciphertext, err := keyRingTestPublic.Encrypt(message, keyRingTestPrivate) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } decrypted, err := keyRingTestPrivate.Decrypt(ciphertext, keyRingTestPublic, GetUnixTime()) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, message.GetString(), decrypted.GetString()) } func TestBinaryMessageEncryption(t *testing.T) { binData, _ := base64.StdEncoding.DecodeString("ExXmnSiQ2QCey20YLH6qlLhkY3xnIBC1AwlIXwK/HvY=") var message = NewPlainMessage(binData) ciphertext, err := keyRingTestPublic.Encrypt(message, keyRingTestPrivate) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } decrypted, err := keyRingTestPrivate.Decrypt(ciphertext, keyRingTestPublic, GetUnixTime()) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, message.GetBinary(), decrypted.GetBinary()) // Decrypt without verifying decrypted, err = keyRingTestPrivate.Decrypt(ciphertext, nil, 0) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, message.GetString(), decrypted.GetString()) } func TestIssue11(t *testing.T) { pgp.latestServerTime = 1559655272 defer func() { pgp.latestServerTime = testTime }() 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) } plainMessage, err := issue11Keyring.Decrypt(pgpMessage, senderKeyring, 0) if err != nil { t.Fatal("Expected no error while decrypting/verifying, got:", err) } assert.Exactly(t, "message from sender", plainMessage.GetString()) } func TestDummy(t *testing.T) { pgp.latestServerTime = 1636644417 defer func() { pgp.latestServerTime = testTime }() 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 = unlockedDummyKey.Lock([]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 = NewPlainMessageFromString( "The secret code is... 1, 2, 3, 4, 5. I repeat: the secret code is... 1, 2, 3, 4, 5", ) ciphertext, err := dummyKeyRing.Encrypt(message, nil) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } split, err := ciphertext.SplitMessage() if err != nil { t.Fatal("Expected no error when splitting, got:", err) } assert.Len(t, split.GetBinaryDataPacket(), 133) // Assert uncompressed encrypted body length decrypted, err := dummyKeyRing.Decrypt(ciphertext, nil, 0) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, message.GetString(), decrypted.GetString()) } func TestSignedMessageDecryption(t *testing.T) { pgpMessage, err := NewPGPMessageFromArmored(readTestFile("message_signed", false)) if err != nil { t.Fatal("Expected no error when unarmoring, got:", err) } decrypted, err := keyRingTestPrivate.Decrypt(pgpMessage, nil, 0) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, readTestFile("message_plaintext", true), decrypted.GetString()) } 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) } decrypted, err := keyRingTestPrivate.Decrypt(pgpMessage, keyRingTestPrivate, 0) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, readTestFile("message_plaintext", true), decrypted.GetString()) } 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) } decrypted, err := keyRingTestPrivate.Decrypt(pgpMessage, keyRingTestPrivate, 0) if err == nil { t.Fatal("Expected verification error when decrypting") } if err.Error() != "Signature Verification Error: Insecure signature" { t.Fatal("Expected verification error when decrypting, got:", err) } assert.Exactly(t, readTestFile("message_plaintext", true), decrypted.GetString()) } func TestMultipleKeyMessageEncryption(t *testing.T) { var message = NewPlainMessageFromString("plain text") assert.Exactly(t, 3, len(keyRingTestMultiple.entities)) ciphertext, err := keyRingTestMultiple.Encrypt(message, keyRingTestPrivate) 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.Data)) 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 decrypted, err := keyRingTestPrivate.Decrypt(ciphertext, keyRingTestPublic, GetUnixTime()) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, message.GetString(), decrypted.GetString()) } func TestMessageGetEncryptionKeyIDs(t *testing.T) { var message = NewPlainMessageFromString("plain text") assert.Exactly(t, 3, len(keyRingTestMultiple.entities)) ciphertext, err := keyRingTestMultiple.Encrypt(message, keyRingTestPrivate) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } ids, ok := ciphertext.GetEncryptionKeyIDs() assert.Exactly(t, 3, len(ids)) assert.True(t, ok) encKey, ok := keyRingTestMultiple.entities[0].EncryptionKey(time.Now()) 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.GetHexEncryptionKeyIDs() 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 = NewPlainMessageFromString("plain text") signature, err := keyRingTestPrivate.SignDetached(message) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } ids, ok := signature.GetSignatureKeyIDs() assert.Exactly(t, 1, len(ids)) assert.True(t, ok) signingKey, ok := keyRingTestPrivate.entities[0].SigningKey(time.Now()) 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.GetHexSignatureKeyIDs() 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 = NewPlainMessageFromString("plain text") ciphertext, err := keyRingTestPublic.Encrypt(message, keyRingTestPrivate) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } comment := "User-defined comment" version := "User-defined version" armored, err := ciphertext.GetArmoredWithCustomHeaders(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 = NewPlainMessageFromString("plain text") ciphertext, err := keyRingTestPublic.Encrypt(message, keyRingTestPrivate) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } comment := "" version := "" armored, err := ciphertext.GetArmoredWithCustomHeaders(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----- ` split, err := NewPGPSplitMessageFromArmored(message) if err != nil { t.Errorf("Couldn't parse split message: %v", err) } if split.KeyPacket == nil { t.Error("Key packet was nil") } if split.DataPacket == nil { t.Error("Data packet was nil") } } golang-github-protonmail-gopenpgp-2.8.1/crypto/mime.go000066400000000000000000000071711472137343600230660ustar00rootroot00000000000000package crypto import ( "bytes" "io/ioutil" "net/mail" "net/textproto" "strings" "github.com/ProtonMail/go-crypto/openpgp" "github.com/ProtonMail/go-crypto/openpgp/packet" gomime "github.com/ProtonMail/go-mime" "github.com/ProtonMail/gopenpgp/v2/constants" "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) } // DecryptMIMEMessage decrypts a MIME message. func (keyRing *KeyRing) DecryptMIMEMessage( message *PGPMessage, verifyKey *KeyRing, callbacks MIMECallbacks, verifyTime int64, ) { decryptedMessage, err := keyRing.Decrypt(message, verifyKey, verifyTime) embeddedSigError, err := separateSigError(err) if err != nil { callbacks.OnError(err) return } body, attachments, attachmentHeaders, err := parseMIME(string(decryptedMessage.GetBinary()), verifyKey) 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 verifyKey != nil { callbacks.OnVerified(constants.SIGNATURE_OK) } bodyContent, bodyMimeType := body.GetBody() bodyContentSanitized := 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 ...*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) (*SignatureVerificationError, error) { sigErr := &SignatureVerificationError{} if errors.As(err, sigErr) { return sigErr, nil } return nil, err } func parseMIME( mimeBody string, verifierKey *KeyRing, ) (*gomime.BodyCollector, []string, []string, error) { mm, err := mail.ReadMessage(strings.NewReader(mimeBody)) if err != nil { return nil, nil, nil, errors.Wrap(err, "gopenpgp: error in reading message") } config := &packet.Config{DefaultCipher: packet.CipherAES256, Time: getTimeGenerator()} h := textproto.MIMEHeader(mm.Header) mmBodyData, err := ioutil.ReadAll(mm.Body) if err != nil { return nil, nil, nil, errors.Wrap(err, "gopenpgp: error in reading message body data") } printAccepter := gomime.NewMIMEPrinter() bodyCollector := gomime.NewBodyCollector(printAccepter) attachmentsCollector := gomime.NewAttachmentsCollector(bodyCollector) mimeVisitor := gomime.NewMimeVisitor(attachmentsCollector) var verifierEntities openpgp.KeyRing if verifierKey != nil { verifierEntities = verifierKey.entities } signatureCollector := newSignatureCollector(mimeVisitor, verifierEntities, config) err = gomime.VisitAll(bytes.NewReader(mmBodyData), h, signatureCollector) if err == nil && verifierKey != nil { err = signatureCollector.verified } return bodyCollector, attachmentsCollector.GetAttachments(), attachmentsCollector.GetAttHeaders(), err } golang-github-protonmail-gopenpgp-2.8.1/crypto/mime_test.go000066400000000000000000000235001472137343600241170ustar00rootroot00000000000000package crypto import ( "errors" "io/ioutil" "path/filepath" "testing" "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 := 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 := NewKeyRing(privateKey) if err != nil { t.Fatal("Cannot create private keyring:", err) } message, err := NewPGPMessageFromArmored(readTestFile("mime_pgpMessage", false)) if err != nil { t.Fatal("Cannot decode armored message:", err) } privateKeyRing.DecryptMIMEMessage( message, nil, &callbacks, GetUnixTime()) } func TestParse(t *testing.T) { body, atts, attHeaders, err := parseMIME(readTestFile("mime_testMessage", false), nil) if err != nil { t.Fatal("Expected no error while parsing message, got:", err) } _ = atts _ = attHeaders bodyData, _ := body.GetBody() assert.Exactly(t, readTestFile("mime_decodedBody", true), bodyData) assert.Exactly(t, readTestFile("mime_decodedBodyHeaders", false), body.GetHeaders()) assert.Exactly(t, 2, len(atts)) } 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) (*KeyRing, error) { armored, err := ioutil.ReadFile(filepath.Clean(file)) if err != nil { return nil, err } key, err := NewKeyFromArmored(string(armored)) if err != nil { return nil, err } unlockedKey, err := key.Unlock([]byte(passphrase)) if err != nil { return nil, err } keyRing, err := NewKeyRing(unlockedKey) if err != nil { return nil, err } return keyRing, nil } func loadPublicKeyRing(file string) (*KeyRing, error) { armored, err := ioutil.ReadFile(filepath.Clean(file)) if err != nil { return nil, err } key, err := NewKeyFromArmored(string(armored)) if err != nil { return nil, err } if key.IsPrivate() { publicKey, err := key.GetPublicKey() if err != nil { return nil, err } key, err = NewKey(publicKey) if err != nil { return nil, err } } keyRing, err := NewKeyRing(key) if err != nil { return nil, err } return keyRing, nil } func loadMessage(file string) (*PGPMessage, error) { armored, err := ioutil.ReadFile(filepath.Clean(file)) if err != nil { return nil, err } message, err := NewPGPMessageFromArmored(string(armored)) if err != nil { return nil, err } return message, 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{} decryptionKeyRing.DecryptMIMEMessage(message, verificationKeyRing, callbacks, 0) 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 := &SignatureVerificationError{} if errors.As(err, &sigErr) { return sigErr.Status } t.Errorf("Expected a signature verification error, got %v", err) return -1 } func compareErrors(expected []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 = []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 = []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 = []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 = []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 = []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 = []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 = []SignatureVerificationError{newSignatureNoVerifier(), newSignatureFailed(nil)} compareErrors(expectedErrors, callbackResults.onError, t) expectedStatus := []int{3} compareStatus(expectedStatus, callbackResults.onVerified, t) } golang-github-protonmail-gopenpgp-2.8.1/crypto/password.go000066400000000000000000000131761472137343600240030ustar00rootroot00000000000000package crypto import ( "bytes" "io" "github.com/ProtonMail/go-crypto/openpgp" pgpErrors "github.com/ProtonMail/go-crypto/openpgp/errors" "github.com/ProtonMail/go-crypto/openpgp/packet" "github.com/pkg/errors" ) // EncryptMessageWithPassword encrypts a PlainMessage to PGPMessage with a // SymmetricKey. // * message : The plain data as a PlainMessage. // * password: A password that will be derived into an encryption key. // * output : The encrypted data as PGPMessage. func EncryptMessageWithPassword(message *PlainMessage, password []byte) (*PGPMessage, error) { encrypted, err := passwordEncrypt(message, password) if err != nil { return nil, err } return NewPGPMessage(encrypted), nil } // DecryptMessageWithPassword decrypts password protected pgp binary messages. // * encrypted: The encrypted data as PGPMessage. // * password: A password that will be derived into an encryption key. // * output: The decrypted data as PlainMessage. func DecryptMessageWithPassword(message *PGPMessage, password []byte) (*PlainMessage, error) { return passwordDecrypt(message.NewReader(), password) } // 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{ V6: s.Version == 6, Key: key, Algo: getAlgo(cipherFunc), } if err = sk.checkSize(); 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) ([]byte, error) { outbuf := &bytes.Buffer{} cf, err := sk.GetCipherFunc() if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to encrypt session key with password") } if len(password) == 0 { return nil, errors.New("gopenpgp: password can't be empty") } if err = sk.checkSize(); err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to encrypt session key with password") } config := &packet.Config{ DefaultCipher: cf, } err = packet.SerializeSymmetricKeyEncryptedReuseKey(outbuf, sk.Key, password, config) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to encrypt session key with password") } return outbuf.Bytes(), nil } // ----- INTERNAL FUNCTIONS ------ func passwordEncrypt(message *PlainMessage, password []byte) ([]byte, error) { var outBuf bytes.Buffer config := &packet.Config{ DefaultCipher: packet.CipherAES256, Time: getTimeGenerator(), } hints := &openpgp.FileHints{ IsBinary: message.IsBinary(), FileName: message.Filename, ModTime: message.getFormattedTime(), } encryptWriter, err := openpgp.SymmetricallyEncrypt(&outBuf, password, hints, config) if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in encrypting message symmetrically") } _, err = encryptWriter.Write(message.GetBinary()) if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in writing data to message") } err = encryptWriter.Close() if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in closing writer") } return outBuf.Bytes(), nil } func passwordDecrypt(encryptedIO io.Reader, password []byte) (*PlainMessage, error) { firstTimeCalled := true var prompt = 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") } config := &packet.Config{ Time: getTimeGenerator(), } var emptyKeyRing openpgp.EntityList md, err := openpgp.ReadMessage(encryptedIO, emptyKeyRing, prompt, config) if err != nil { // 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") } messageBuf := bytes.NewBuffer(nil) _, err = io.Copy(messageBuf, md.UnverifiedBody) if errors.Is(err, pgpErrors.ErrMDCHashMismatch) { // This MDC error may also be triggered if the password is correct, but the encrypted data was corrupted. // To avoid confusion, we do not inform the user about the second possibility. return nil, errors.New("gopenpgp: wrong password in symmetric decryption") } if err != nil { // Parsing errors after decryption, triggered before parsing the MDC packet, are also usually the result of wrong password return nil, errors.New("gopenpgp: error in reading password protected message: wrong password or malformed message") } return &PlainMessage{ Data: messageBuf.Bytes(), TextType: !md.LiteralData.IsBinary, Filename: md.LiteralData.FileName, Time: md.LiteralData.Time, }, nil } golang-github-protonmail-gopenpgp-2.8.1/crypto/sanitize_string.go000066400000000000000000000001741472137343600253470ustar00rootroot00000000000000package crypto import "strings" func sanitizeString(input string) string { return strings.ToValidUTF8(input, "\ufffd") } golang-github-protonmail-gopenpgp-2.8.1/crypto/sessionkey.go000066400000000000000000000326011472137343600243270ustar00rootroot00000000000000package crypto import ( "bytes" "encoding/base64" "fmt" "io" "time" "github.com/ProtonMail/gopenpgp/v2/constants" "github.com/pkg/errors" "github.com/ProtonMail/go-crypto/openpgp" pgpErrors "github.com/ProtonMail/go-crypto/openpgp/errors" "github.com/ProtonMail/go-crypto/openpgp/packet" ) // SessionKey stores a decrypted session key. type SessionKey struct { V6 bool // The decrypted binary session key. Key []byte // The symmetric encryption algorithm used with this key. Algo string } 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, } 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. func (sk *SessionKey) GetCipherFunc() (packet.CipherFunction, error) { if sk.V6 { return 0, nil } cf, ok := symKeyAlgos[sk.Algo] if !ok { return cf, errors.New("gopenpgp: unsupported cipher function: " + sk.Algo) } return cf, nil } // 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() (*SessionKey, error) { return GenerateSessionKeyAlgo(constants.AES256) } func NewSessionKeyFromToken(token []byte, algo string) *SessionKey { return &SessionKey{ Key: clone(token), Algo: algo, V6: 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 err := sk.checkSize(); err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to decrypt session key") } return sk, nil } // Encrypt encrypts a PlainMessage to PGPMessage with a SessionKey. // * message : The plain data as a PlainMessage. // * output : The encrypted data as PGPMessage. func (sk *SessionKey) Encrypt(message *PlainMessage) ([]byte, error) { return encryptWithSessionKey(message, sk, nil, false, nil) } // EncryptAndSign encrypts a PlainMessage to PGPMessage with a SessionKey and signs it with a Private key. // * message : The plain data as a PlainMessage. // * signKeyRing: The KeyRing to sign the message // * output : The encrypted data as PGPMessage. func (sk *SessionKey) EncryptAndSign(message *PlainMessage, signKeyRing *KeyRing) ([]byte, error) { return encryptWithSessionKey(message, sk, signKeyRing, false, nil) } // EncryptAndSignWithContext encrypts a PlainMessage to PGPMessage with a SessionKey and signs it with a Private key. // * message : The plain data as a PlainMessage. // * signKeyRing: The KeyRing to sign the message // * output : The encrypted data as PGPMessage. // * signingContext : (optional) the context for the signature. func (sk *SessionKey) EncryptAndSignWithContext(message *PlainMessage, signKeyRing *KeyRing, signingContext *SigningContext) ([]byte, error) { return encryptWithSessionKey(message, sk, signKeyRing, false, signingContext) } // EncryptWithCompression encrypts with compression support a PlainMessage to PGPMessage with a SessionKey. // * message : The plain data as a PlainMessage. // * output : The encrypted data as PGPMessage. func (sk *SessionKey) EncryptWithCompression(message *PlainMessage) ([]byte, error) { return encryptWithSessionKey(message, sk, nil, true, nil) } func encryptWithSessionKey( message *PlainMessage, sk *SessionKey, signKeyRing *KeyRing, compress bool, signingContext *SigningContext, ) ([]byte, error) { var encBuf = new(bytes.Buffer) encryptWriter, signWriter, err := encryptStreamWithSessionKey( NewPlainMessageMetadata( message.IsBinary(), message.Filename, int64(message.Time), ), encBuf, sk, signKeyRing, compress, signingContext, ) if err != nil { return nil, err } if signKeyRing != nil { _, err = signWriter.Write(message.GetBinary()) if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in writing signed message") } err = signWriter.Close() if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in closing signing writer") } } else { _, err = encryptWriter.Write(message.GetBinary()) } if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in writing message") } err = encryptWriter.Close() if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in closing encryption writer") } return encBuf.Bytes(), nil } func encryptStreamWithSessionKey( plainMessageMetadata *PlainMessageMetadata, dataPacketWriter io.Writer, sk *SessionKey, signKeyRing *KeyRing, compress bool, signingContext *SigningContext, ) (encryptWriter, signWriter io.WriteCloser, err error) { dc, err := sk.GetCipherFunc() if err != nil { return nil, nil, errors.Wrap(err, "gopenpgp: unable to encrypt with session key") } config := &packet.Config{ Time: getTimeGenerator(), DefaultCipher: dc, } var signEntity *openpgp.Entity if signKeyRing != nil { signEntity, err = signKeyRing.getSigningEntity() if err != nil { return nil, nil, errors.Wrap(err, "gopenpgp: unable to sign") } } if compress { config.DefaultCompressionAlgo = constants.DefaultCompression config.CompressionConfig = &packet.CompressionConfig{Level: constants.DefaultCompressionLevel} } if signingContext != nil { config.SignatureNotations = append(config.SignatureNotations, signingContext.getNotation()) } if plainMessageMetadata == nil { // Use sensible default metadata plainMessageMetadata = &PlainMessageMetadata{ IsBinary: true, Filename: "", ModTime: GetUnixTime(), } } return encryptStreamWithSessionKeyAndConfig( plainMessageMetadata.IsBinary, plainMessageMetadata.Filename, uint32(plainMessageMetadata.ModTime), dataPacketWriter, sk, signEntity, config, ) } func encryptStreamWithSessionKeyAndConfig( isBinary bool, filename string, modTime uint32, dataPacketWriter io.Writer, sk *SessionKey, signEntity *openpgp.Entity, config *packet.Config, ) (encryptWriter, signWriter io.WriteCloser, err error) { encryptWriter, err = packet.SerializeSymmetricallyEncrypted( dataPacketWriter, config.Cipher(), config.AEAD() != nil, packet.CipherSuite{Cipher: config.Cipher(), Mode: config.AEAD().Mode()}, sk.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 signEntity != nil { hints := &openpgp.FileHints{ IsBinary: isBinary, FileName: filename, ModTime: time.Unix(int64(modTime), 0), } signWriter, err = openpgp.Sign(encryptWriter, signEntity, hints, config) if err != nil { return nil, nil, errors.Wrap(err, "gopenpgp: unable to sign") } } else { encryptWriter, err = packet.SerializeLiteral( encryptWriter, isBinary, filename, modTime, ) if err != nil { return nil, nil, errors.Wrap(err, "gopenpgp: unable to serialize") } } return encryptWriter, signWriter, nil } // Decrypt decrypts pgp data packets using directly a session key. // * encrypted: PGPMessage. // * output: PlainMessage. func (sk *SessionKey) Decrypt(dataPacket []byte) (*PlainMessage, error) { return sk.DecryptAndVerify(dataPacket, nil, 0) } // DecryptAndVerify decrypts pgp data packets using directly a session key and verifies embedded signatures. // * encrypted: PGPMessage. // * verifyKeyRing: KeyRing with verification public keys // * verifyTime: when should the signature be valid, as timestamp. If 0 time verification is disabled. // * output: PlainMessage. func (sk *SessionKey) DecryptAndVerify(dataPacket []byte, verifyKeyRing *KeyRing, verifyTime int64) (*PlainMessage, error) { return decryptWithSessionKeyAndContext( sk, dataPacket, verifyKeyRing, verifyTime, nil, ) } // DecryptAndVerifyWithContext decrypts pgp data packets using directly a session key and verifies embedded signatures. // * encrypted: PGPMessage. // * verifyKeyRing: KeyRing with verification public keys // * verifyTime: when should the signature be valid, as timestamp. If 0 time verification is disabled. // * output: PlainMessage. // * verificationContext (optional): context for the signature verification. func (sk *SessionKey) DecryptAndVerifyWithContext(dataPacket []byte, verifyKeyRing *KeyRing, verifyTime int64, verificationContext *VerificationContext) (*PlainMessage, error) { return decryptWithSessionKeyAndContext( sk, dataPacket, verifyKeyRing, verifyTime, verificationContext, ) } func decryptWithSessionKeyAndContext( sk *SessionKey, dataPacket []byte, verifyKeyRing *KeyRing, verifyTime int64, verificationContext *VerificationContext, ) (*PlainMessage, error) { var messageReader = bytes.NewReader(dataPacket) md, err := decryptStreamWithSessionKey(sk, messageReader, verifyKeyRing, verificationContext) if err != nil { return nil, err } messageBuf := new(bytes.Buffer) _, err = messageBuf.ReadFrom(md.UnverifiedBody) if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in reading message body") } if verifyKeyRing != nil { processSignatureExpiration(md, verifyTime) err = verifyDetailsSignature(md, verifyKeyRing, verificationContext) } return &PlainMessage{ Data: messageBuf.Bytes(), TextType: !md.LiteralData.IsBinary, Filename: md.LiteralData.FileName, Time: md.LiteralData.Time, }, err } func decryptStreamWithSessionKey( sk *SessionKey, messageReader io.Reader, verifyKeyRing *KeyRing, verificationContext *VerificationContext, ) (*openpgp.MessageDetails, error) { var decrypted io.ReadCloser var keyring openpgp.EntityList // Read symmetrically encrypted data packet 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.SymmetricallyEncrypted, *packet.AEADEncrypted: if symPacket, ok := p.(*packet.SymmetricallyEncrypted); ok { if !symPacket.IntegrityProtected { return nil, errors.New("gopenpgp: message is not authenticated") } } dc, err := sk.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, sk.Key) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to decrypt symmetric packet") } default: return nil, errors.New("gopenpgp: invalid packet type") } config := &packet.Config{ Time: getTimeGenerator(), } if verificationContext != nil { config.KnownNotations = map[string]bool{constants.SignatureContextName: true} } // Push decrypted packet as literal packet and use openpgp's reader if verifyKeyRing != nil { keyring = verifyKeyRing.entities } else { keyring = openpgp.EntityList{} } md, err := openpgp.ReadMessage(decrypted, keyring, nil, config) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to decode symmetric packet") } md.UnverifiedBody = checkReader{decrypted, md.UnverifiedBody} return md, nil } func (sk *SessionKey) checkSize() error { if sk.V6 { if len(sk.Key) == 0 { return errors.New("empty session key") } return nil } 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 { if cipher == 0 { return "" } algo := constants.AES256 for k, v := range symKeyAlgos { if v == cipher { algo = k break } } return algo } golang-github-protonmail-gopenpgp-2.8.1/crypto/sessionkey_streaming.go000066400000000000000000000125141472137343600264010ustar00rootroot00000000000000package crypto import ( "github.com/pkg/errors" ) 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() } // EncryptStream is used to encrypt data as a Writer. // It takes a writer for the encrypted data packet and returns a writer for the plaintext data. // If signKeyRing is not nil, it is used to do an embedded signature. func (sk *SessionKey) EncryptStream( dataPacketWriter Writer, plainMessageMetadata *PlainMessageMetadata, signKeyRing *KeyRing, ) (plainMessageWriter WriteCloser, err error) { return sk.encryptStream( dataPacketWriter, plainMessageMetadata, signKeyRing, false, nil, ) } // EncryptStreamWithContext is used to encrypt data as a Writer. // It takes a writer for the encrypted data packet and returns a writer for the plaintext data. // If signKeyRing is not nil, it is used to do an embedded signature. // * signingContext : (optional) the context for the signature. func (sk *SessionKey) EncryptStreamWithContext( dataPacketWriter Writer, plainMessageMetadata *PlainMessageMetadata, signKeyRing *KeyRing, signingContext *SigningContext, ) (plainMessageWriter WriteCloser, err error) { return sk.encryptStream( dataPacketWriter, plainMessageMetadata, signKeyRing, false, signingContext, ) } // EncryptStreamWithCompression is used to encrypt data as a Writer. // The plaintext data is compressed before being encrypted. // It takes a writer for the encrypted data packet and returns a writer for the plaintext data. // If signKeyRing is not nil, it is used to do an embedded signature. // * signingContext : (optional) the context for the signature. func (sk *SessionKey) EncryptStreamWithCompression( dataPacketWriter Writer, plainMessageMetadata *PlainMessageMetadata, signKeyRing *KeyRing, ) (plainMessageWriter WriteCloser, err error) { return sk.encryptStream( dataPacketWriter, plainMessageMetadata, signKeyRing, true, nil, ) } // EncryptStreamWithContextAndCompression is used to encrypt data as a Writer. // The plaintext data is compressed before being encrypted. // It takes a writer for the encrypted data packet and returns a writer for the plaintext data. // If signKeyRing is not nil, it is used to do an embedded signature. // * signingContext : (optional) the context for the signature. func (sk *SessionKey) EncryptStreamWithContextAndCompression( dataPacketWriter Writer, plainMessageMetadata *PlainMessageMetadata, signKeyRing *KeyRing, signingContext *SigningContext, ) (plainMessageWriter WriteCloser, err error) { return sk.encryptStream( dataPacketWriter, plainMessageMetadata, signKeyRing, true, signingContext, ) } func (sk *SessionKey) encryptStream( dataPacketWriter Writer, plainMessageMetadata *PlainMessageMetadata, signKeyRing *KeyRing, compress bool, signingContext *SigningContext, ) (plainMessageWriter WriteCloser, err error) { encryptWriter, signWriter, err := encryptStreamWithSessionKey( plainMessageMetadata, dataPacketWriter, sk, signKeyRing, compress, signingContext, ) if err != nil { return nil, err } if signWriter != nil { plainMessageWriter = &signAndEncryptWriteCloser{signWriter, encryptWriter} } else { plainMessageWriter = encryptWriter } return plainMessageWriter, err } // DecryptStream is used to decrypt a data packet as a Reader. // It takes a reader for the data packet // and returns a PlainMessageReader for the plaintext data. // If verifyKeyRing is not nil, PlainMessageReader.VerifySignature() will // verify the embedded signature with the given key ring and verification time. func (sk *SessionKey) DecryptStream( dataPacketReader Reader, verifyKeyRing *KeyRing, verifyTime int64, ) (plainMessage *PlainMessageReader, err error) { return decryptStreamWithSessionKeyAndContext( sk, dataPacketReader, verifyKeyRing, verifyTime, nil, ) } // DecryptStreamWithContext is used to decrypt a data packet as a Reader. // It takes a reader for the data packet // and returns a PlainMessageReader for the plaintext data. // If verifyKeyRing is not nil, PlainMessageReader.VerifySignature() will // verify the embedded signature with the given key ring and verification time. // * verificationContext (optional): context for the signature verification. func (sk *SessionKey) DecryptStreamWithContext( dataPacketReader Reader, verifyKeyRing *KeyRing, verifyTime int64, verificationContext *VerificationContext, ) (plainMessage *PlainMessageReader, err error) { return decryptStreamWithSessionKeyAndContext( sk, dataPacketReader, verifyKeyRing, verifyTime, verificationContext, ) } func decryptStreamWithSessionKeyAndContext( sessionKey *SessionKey, dataPacketReader Reader, verifyKeyRing *KeyRing, verifyTime int64, verificationContext *VerificationContext, ) (plainMessage *PlainMessageReader, err error) { messageDetails, err := decryptStreamWithSessionKey( sessionKey, dataPacketReader, verifyKeyRing, verificationContext, ) if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in reading message") } return &PlainMessageReader{ messageDetails, verifyKeyRing, verifyTime, false, verificationContext, }, err } golang-github-protonmail-gopenpgp-2.8.1/crypto/sessionkey_streaming_test.go000066400000000000000000000221361472137343600274410ustar00rootroot00000000000000package crypto import ( "bytes" "io" "io/ioutil" "reflect" "testing" "github.com/pkg/errors" ) func TestSessionKey_EncryptDecryptStream(t *testing.T) { messageBytes := []byte("Hello World!") messageReader := bytes.NewReader(messageBytes) var dataPacketBuf bytes.Buffer messageWriter, err := testSessionKey.EncryptStream( &dataPacketBuf, testMeta, keyRingTestPrivate, ) if err != nil { t.Fatal("Expected no error while encrypting stream with session key, got:", err) } bufferSize := 2 buffer := make([]byte, bufferSize) reachedEnd := false for !reachedEnd { n, err := messageReader.Read(buffer) if err != nil { if errors.Is(err, io.EOF) { reachedEnd = true } else { t.Fatal("Expected no error while reading data, got:", err) } } writtenTotal := 0 for writtenTotal < n { written, err := messageWriter.Write(buffer[writtenTotal:n]) if err != nil { t.Fatal("Expected no error while writing data, got:", err) } writtenTotal += written } } err = messageWriter.Close() if err != nil { t.Fatal("Expected no error while closing plaintext writer, got:", err) } dataPacket := dataPacketBuf.Bytes() decryptedReader, err := testSessionKey.DecryptStream( bytes.NewReader(dataPacket), keyRingTestPublic, GetUnixTime(), ) if err != nil { t.Fatal("Expected no error while calling DecryptStream, got:", err) } decryptedBytes, err := ioutil.ReadAll(decryptedReader) if err != nil { t.Fatal("Expected no error while reading the decrypted data, got:", err) } err = decryptedReader.VerifySignature() if err != nil { t.Fatal("Expected no error while verifying the signature, got:", err) } if !bytes.Equal(decryptedBytes, messageBytes) { t.Fatalf("Expected the decrypted data to be %s got %s", string(decryptedBytes), string(messageBytes)) } decryptedMeta := decryptedReader.GetMetadata() if !reflect.DeepEqual(testMeta, decryptedMeta) { t.Fatalf("Expected the decrypted metadata to be %v got %v", testMeta, decryptedMeta) } } func TestSessionKey_EncryptDecryptStreamWithContext(t *testing.T) { messageBytes := []byte("Hello World!") messageReader := bytes.NewReader(messageBytes) var dataPacketBuf bytes.Buffer testContext := "test-context" messageWriter, err := testSessionKey.EncryptStreamWithContext( &dataPacketBuf, testMeta, keyRingTestPrivate, NewSigningContext(testContext, true), ) if err != nil { t.Fatal("Expected no error while encrypting, got:", err) } _, err = io.Copy(messageWriter, messageReader) if err != nil { t.Fatal("Expected no error while copying plaintext, got:", err) } err = messageWriter.Close() if err != nil { t.Fatal("Expected no error while closing plaintext writer, got:", err) } dataPacket := dataPacketBuf.Bytes() decryptedReader, err := testSessionKey.DecryptStreamWithContext( bytes.NewReader(dataPacket), keyRingTestPublic, GetUnixTime(), NewVerificationContext(testContext, true, 0), ) if err != nil { t.Fatal("Expected no error while calling DecryptStream, got:", err) } decryptedBytes, err := ioutil.ReadAll(decryptedReader) if err != nil { t.Fatal("Expected no error while reading the decrypted data, got:", err) } err = decryptedReader.VerifySignature() if err != nil { t.Fatal("Expected no error while verifying the signature, got:", err) } if !bytes.Equal(decryptedBytes, messageBytes) { t.Fatalf("Expected the decrypted data to be %s got %s", string(decryptedBytes), string(messageBytes)) } decryptedMeta := decryptedReader.GetMetadata() if !reflect.DeepEqual(testMeta, decryptedMeta) { t.Fatalf("Expected the decrypted metadata to be %v got %v", testMeta, decryptedMeta) } } func TestSessionKey_EncryptDecryptStreamWithContextAndCompression(t *testing.T) { messageBytes := []byte("Hello World!") messageReader := bytes.NewReader(messageBytes) var dataPacketBuf bytes.Buffer testContext := "test-context" messageWriter, err := testSessionKey.EncryptStreamWithContextAndCompression( &dataPacketBuf, testMeta, keyRingTestPrivate, NewSigningContext(testContext, true), ) if err != nil { t.Fatal("Expected no error while encrypting, got:", err) } _, err = io.Copy(messageWriter, messageReader) if err != nil { t.Fatal("Expected no error while copying plaintext, got:", err) } err = messageWriter.Close() if err != nil { t.Fatal("Expected no error while closing plaintext writer, got:", err) } dataPacket := dataPacketBuf.Bytes() decryptedReader, err := testSessionKey.DecryptStreamWithContext( bytes.NewReader(dataPacket), keyRingTestPublic, GetUnixTime(), NewVerificationContext(testContext, true, 0), ) if err != nil { t.Fatal("Expected no error while calling DecryptStream, got:", err) } decryptedBytes, err := ioutil.ReadAll(decryptedReader) if err != nil { t.Fatal("Expected no error while reading the decrypted data, got:", err) } err = decryptedReader.VerifySignature() if err != nil { t.Fatal("Expected no error while verifying the signature, got:", err) } if !bytes.Equal(decryptedBytes, messageBytes) { t.Fatalf("Expected the decrypted data to be %s got %s", string(decryptedBytes), string(messageBytes)) } decryptedMeta := decryptedReader.GetMetadata() if !reflect.DeepEqual(testMeta, decryptedMeta) { t.Fatalf("Expected the decrypted metadata to be %v got %v", testMeta, decryptedMeta) } } func TestSessionKey_EncryptStreamCompatible(t *testing.T) { enc := func(w io.Writer, meta *PlainMessageMetadata, kr *KeyRing) (io.WriteCloser, error) { return testSessionKey.EncryptStream(w, meta, kr) } testSessionKey_EncryptStreamCompatible(enc, t) } func TestSessionKey_EncryptStreamWithCompressionCompatible(t *testing.T) { enc := func(w io.Writer, meta *PlainMessageMetadata, kr *KeyRing) (io.WriteCloser, error) { return testSessionKey.EncryptStreamWithCompression(w, meta, kr) } testSessionKey_EncryptStreamCompatible(enc, t) } type sessionKeyEncryptionFunction = func(io.Writer, *PlainMessageMetadata, *KeyRing) (io.WriteCloser, error) func testSessionKey_EncryptStreamCompatible(enc sessionKeyEncryptionFunction, t *testing.T) { messageBytes := []byte("Hello World!") messageReader := bytes.NewReader(messageBytes) var dataPacketBuf bytes.Buffer messageWriter, err := enc( &dataPacketBuf, testMeta, keyRingTestPrivate, ) if err != nil { t.Fatal("Expected no error while encrypting stream with session key, got:", err) } bufferSize := 2 buffer := make([]byte, bufferSize) reachedEnd := false for !reachedEnd { n, err := messageReader.Read(buffer) if err != nil { if errors.Is(err, io.EOF) { reachedEnd = true } else { t.Fatal("Expected no error while reading data, got:", err) } } writtenTotal := 0 for writtenTotal < n { written, err := messageWriter.Write(buffer[writtenTotal:n]) if err != nil { t.Fatal("Expected no error while writing data, got:", err) } writtenTotal += written } } err = messageWriter.Close() if err != nil { t.Fatal("Expected no error while closing plaintext writer, got:", err) } dataPacket := dataPacketBuf.Bytes() decryptedMsg, err := testSessionKey.DecryptAndVerify( dataPacket, keyRingTestPublic, GetUnixTime(), ) if err != nil { t.Fatal("Expected no error while calling DecryptAndVerify, got:", err) } decryptedBytes := decryptedMsg.Data 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 testMeta.IsBinary != decryptedMsg.IsBinary() { t.Fatalf("Expected isBinary to be %t got %t", testMeta.IsBinary, decryptedMsg.IsBinary()) } if testMeta.Filename != decryptedMsg.GetFilename() { t.Fatalf("Expected filename to be %s got %s", testMeta.Filename, decryptedMsg.GetFilename()) } if testMeta.ModTime != int64(decryptedMsg.GetTime()) { t.Fatalf("Expected modification time to be %d got %d", testMeta.ModTime, int64(decryptedMsg.GetTime())) } } func TestSessionKey_DecryptStreamCompatible(t *testing.T) { messageBytes := []byte("Hello World!") dataPacket, err := testSessionKey.EncryptAndSign( &PlainMessage{ Data: messageBytes, TextType: !testMeta.IsBinary, Time: uint32(testMeta.ModTime), Filename: testMeta.Filename, }, keyRingTestPrivate, ) if err != nil { t.Fatal("Expected no error while encrypting plaintext, got:", err) } decryptedReader, err := testSessionKey.DecryptStream( bytes.NewReader(dataPacket), keyRingTestPublic, GetUnixTime(), ) if err != nil { t.Fatal("Expected no error while calling DecryptStream, got:", err) } decryptedBytes, err := ioutil.ReadAll(decryptedReader) if err != nil { t.Fatal("Expected no error while reading the decrypted data, got:", err) } err = decryptedReader.VerifySignature() if err != nil { t.Fatal("Expected no error while verifying the signature, got:", err) } if !bytes.Equal(decryptedBytes, messageBytes) { t.Fatalf("Expected the decrypted data to be %s got %s", string(decryptedBytes), string(messageBytes)) } decryptedMeta := decryptedReader.GetMetadata() if !reflect.DeepEqual(testMeta, decryptedMeta) { t.Fatalf("Expected the decrypted metadata to be %v got %v", testMeta, decryptedMeta) } } golang-github-protonmail-gopenpgp-2.8.1/crypto/sessionkey_test.go000066400000000000000000000331061472137343600253670ustar00rootroot00000000000000package crypto import ( "encoding/base64" "encoding/hex" "errors" "io/ioutil" "testing" "github.com/ProtonMail/gopenpgp/v2/constants" "github.com/stretchr/testify/assert" ) var testSessionKey *SessionKey func init() { var err error testSessionKey, err = GenerateSessionKey() if err != nil { panic("Expected no error while generating random session key with default algorithm, 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) { keyPacket, err := keyRingTestPublic.EncryptSessionKey(testSessionKey) if err != nil { t.Fatal("Expected no error while generating key packet, got:", err) } // Password defined in keyring_test outputSymmetricKey, err := keyRingTestPrivate.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) { keyPacket, err := keyRingTestMultiple.EncryptSessionKey(testSessionKey) if err != nil { t.Fatal("Expected no error while generating key packet, got:", err) } // Password defined in keyring_test outputSymmetricKey, err := keyRingTestPrivate.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") keyPacket, err := EncryptSessionKeyWithPassword(testSessionKey, password) if err != nil { t.Fatal("Expected no error while generating key packet, got:", err) } wrongSymmetricKey, err := DecryptSessionKeyWithPassword(keyPacket, []byte("Wrong password")) if err != nil { assert.EqualError(t, err, "gopenpgp: unable to decrypt any packet") } else { assert.NotEqual(t, testSessionKey, wrongSymmetricKey) } outputSymmetricKey, err := DecryptSessionKeyWithPassword(keyPacket, password) 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) if err == nil { t.Fatal("Expected error while generating key packet with wrong sized key") } } func TestDataPacketEncryption(t *testing.T) { var message = NewPlainMessageFromString( "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 dataPacket, err := testSessionKey.Encrypt(message) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } assert.Len(t, dataPacket, 133) // Assert uncompressed encrypted body length // Decrypt data with wrong session key wrongKey := SessionKey{ Key: []byte("wrong pass"), Algo: constants.AES256, } _, err = wrongKey.Decrypt(dataPacket) assert.NotNil(t, err) // Decrypt data with the good session key decrypted, err := testSessionKey.Decrypt(dataPacket) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, message.GetString(), decrypted.GetString()) // Encrypt session key assert.Exactly(t, 3, len(keyRingTestMultiple.entities)) keyPacket, err := keyRingTestMultiple.EncryptSessionKey(testSessionKey) if err != nil { t.Fatal("Unable to encrypt key packet, got:", err) } // Join key packet and data packet in single message splitMessage := NewPGPSplitMessage(keyPacket, dataPacket) // Armor and un-armor message. In alternative it can also be done with NewPgpMessage(splitMessage.GetBinary()) armored, err := splitMessage.GetArmored() 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.GetEncryptionKeyIDs() assert.True(t, ok) assert.Exactly(t, 3, len(ids)) // Test if final decryption succeeds finalMessage, err := keyRingTestPrivate.Decrypt(pgpMessage, nil, 0) if err != nil { t.Fatal("Unable to decrypt joined keypacket and datapacket, got:", err) } assert.Exactly(t, message.GetString(), finalMessage.GetString()) } func TestDataPacketEncryptionAndSignature(t *testing.T) { var message = NewPlainMessageFromString( "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 dataPacket, err := testSessionKey.EncryptAndSign(message, keyRingTestPrivate) 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, } _, err = wrongKey.Decrypt(dataPacket) assert.NotNil(t, err) // Decrypt data with the good session key decrypted, err := testSessionKey.Decrypt(dataPacket) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, message.GetString(), decrypted.GetString()) // 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) } castedErr := &SignatureVerificationError{} _, err = testSessionKey.DecryptAndVerify(dataPacket, ecKeyRing, GetUnixTime()) if err == nil || !errors.As(err, castedErr) { t.Fatal("No error or wrong error returned for verification failure", err) } // Decrypt & verify data with the good session key and keyring decrypted, err = testSessionKey.DecryptAndVerify(dataPacket, keyRingTestPublic, GetUnixTime()) if err != nil { t.Fatal("Expected no error when decrypting & verifying, got:", err) } assert.Exactly(t, message.GetString(), decrypted.GetString()) // Encrypt session key assert.Exactly(t, 3, len(keyRingTestMultiple.entities)) keyPacket, err := keyRingTestMultiple.EncryptSessionKey(testSessionKey) if err != nil { t.Fatal("Unable to encrypt key packet, got:", err) } // Join key packet and data packet in single message splitMessage := NewPGPSplitMessage(keyPacket, dataPacket) // Armor and un-armor message. In alternative it can also be done with NewPgpMessage(splitMessage.GetBinary()) armored, err := splitMessage.GetArmored() 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.GetEncryptionKeyIDs() assert.True(t, ok) assert.Exactly(t, 3, len(ids)) // Test with bad verification key succeeds _, err = keyRingTestPrivate.Decrypt(pgpMessage, ecKeyRing, GetUnixTime()) if err == nil || !errors.As(err, castedErr) { t.Fatal("No error or wrong error returned for verification failure") } // Test if final decryption & verification succeeds finalMessage, err := keyRingTestPrivate.Decrypt(pgpMessage, keyRingTestPublic, GetUnixTime()) if err != nil { t.Fatal("Unable to decrypt and verify joined keypacket and datapacket, got:", err) } assert.Exactly(t, message.GetString(), finalMessage.GetString()) } func TestDataPacketEncryptionAndSignatureWithContext(t *testing.T) { var message = NewPlainMessageFromString( "The secret code is... 1, 2, 3, 4, 5. I repeat: the secret code is... 1, 2, 3, 4, 5", ) var testContext = "test-context" // Encrypt data with session key dataPacket, err := testSessionKey.EncryptAndSignWithContext(message, keyRingTestPrivate, NewSigningContext(testContext, true)) if err != nil { t.Fatal("Expected no error when encrypting and signing, got:", err) } // Decrypt & verify data with the good session key and keyring decrypted, err := testSessionKey.DecryptAndVerifyWithContext( dataPacket, keyRingTestPublic, GetUnixTime(), NewVerificationContext(testContext, true, 0), ) if err != nil { t.Fatal("Expected no error when decrypting & verifying, got:", err) } assert.Exactly(t, message.GetString(), decrypted.GetString()) } func TestDataPacketDecryption(t *testing.T) { pgpMessage, err := NewPGPMessageFromArmored(readTestFile("message_signed", false)) if err != nil { t.Fatal("Expected no error when unarmoring, got:", err) } split, err := pgpMessage.SeparateKeyAndData(1024, 0) // Test passing parameters for backwards compatibility if err != nil { t.Fatal("Expected no error when splitting, got:", err) } sessionKey, err := keyRingTestPrivate.DecryptSessionKey(split.GetBinaryKeyPacket()) if err != nil { t.Fatal("Expected no error when decrypting session key, got:", err) } decrypted, err := sessionKey.Decrypt(split.GetBinaryDataPacket()) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, readTestFile("message_plaintext", true), decrypted.GetString()) } func TestMDCFailDecryption(t *testing.T) { pgpMessage, err := NewPGPMessageFromArmored(readTestFile("message_badmdc", false)) if err != nil { t.Fatal("Expected no error when unarmoring, got:", err) } split, err := pgpMessage.SplitMessage() if err != nil { t.Fatal("Expected no error when splitting, got:", err) } sk, _ := hex.DecodeString("F76D3236E4F8A38785C50BDE7167475E95360BCE67A952710F6C16F18BB0655E") sessionKey := NewSessionKeyFromToken(sk, "aes256") _, err = sessionKey.Decrypt(split.GetBinaryDataPacket()) assert.NotNil(t, err) } func TestSessionKeyClear(t *testing.T) { testSessionKey.Clear() assertMemCleared(t, testSessionKey.Key) } func TestDataPacketEncryptionWithCompression(t *testing.T) { var message = NewPlainMessageFromString( "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 dataPacket, err := testSessionKey.EncryptWithCompression(message) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } assert.Len(t, dataPacket, 117) // Assert compressed encrypted body length // Decrypt data with the good session key decrypted, err := testSessionKey.Decrypt(dataPacket) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, message.GetString(), decrypted.GetString()) } 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()) } _, err = ukr.DecryptSessionKey(keyPacket) assert.Error(t, err, "gopenpgp: unable to decrypt session key") } func TestAEADDataPacketDecryption(t *testing.T) { pgpMessageData, err := ioutil.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) split, err := pgpMessage.SplitMessage() if err != nil { t.Fatal("Expected no error when splitting, 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() sessionKey, err := kR.DecryptSessionKey(split.GetBinaryKeyPacket()) if err != nil { t.Fatal("Expected no error when decrypting session key, got:", err) } decrypted, err := sessionKey.Decrypt(split.GetBinaryDataPacket()) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, "hello world\n", decrypted.GetString()) } func TestSEDDecryption(t *testing.T) { pgpMessageData, err := ioutil.ReadFile("testdata/sed_message") if err != nil { t.Fatal("Expected no error when reading message data, got:", err) } pgpMessage, err := NewPGPMessageFromArmored(string(pgpMessageData)) if err != nil { t.Fatal("Expected no error when creating message, got:", err) } split, err := pgpMessage.SplitMessage() if err != nil { t.Fatal("Expected no error when splitting, got:", err) } privateKey, err := NewKeyFromArmored(readTestFile("sed_key", false)) if err != nil { t.Fatal("Expected no error when unarmoring key, got:", err) } kR, err := NewKeyRing(privateKey) if err != nil { t.Fatal("Expected no error when creating the keyring, got:", err) } defer kR.ClearPrivateParams() sessionKey, err := kR.DecryptSessionKey(split.GetBinaryKeyPacket()) if err != nil { t.Fatal("Expected no error when decrypting session key, got:", err) } _, err = sessionKey.Decrypt(split.GetBinaryDataPacket()) if err == nil { t.Fatal("sed packets without authentication should not be allowed", err) } } golang-github-protonmail-gopenpgp-2.8.1/crypto/signature.go000066400000000000000000000227571472137343600241470ustar00rootroot00000000000000package crypto import ( "bytes" "crypto" "fmt" "io" "math" "time" "github.com/ProtonMail/go-crypto/openpgp" pgpErrors "github.com/ProtonMail/go-crypto/openpgp/errors" "github.com/ProtonMail/go-crypto/openpgp/packet" "github.com/pkg/errors" "github.com/ProtonMail/gopenpgp/v2/constants" "github.com/ProtonMail/gopenpgp/v2/internal" ) // allowedHashes stores the allowed OpenPGP hashes that can be used in a // message signature hash. var allowedHashes = []crypto.Hash{ crypto.SHA224, crypto.SHA256, crypto.SHA384, crypto.SHA512, crypto.SHA3_256, crypto.SHA3_512, } // SignatureVerificationError is returned from Decrypt and VerifyDetached // functions when signature verification fails. type SignatureVerificationError struct { Status int Message string Cause error } // 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 // ------------------ // 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, } } // newSignatureInsecure creates a new SignatureVerificationError, type // SignatureFailed, with a message describing the signature as insecure. func newSignatureInsecure() SignatureVerificationError { return SignatureVerificationError{ Status: constants.SIGNATURE_FAILED, Message: "Insecure signature", } } // 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 add a margin to the creationTime check. func processSignatureExpiration(md *openpgp.MessageDetails, verifyTime int64) { if !errors.Is(md.SignatureError, pgpErrors.ErrSignatureExpired) { return } if verifyTime == 0 { // verifyTime = 0: time check disabled, everything is okay md.SignatureError = nil return } created := md.Signature.CreationTime.Unix() expires := int64(math.MaxInt64) if md.Signature.SigLifetimeSecs != nil { expires = int64(*md.Signature.SigLifetimeSecs) + created } if created-internal.CreationTimeOffset <= verifyTime && verifyTime <= expires { md.SignatureError = nil } } // verifyDetailsSignature verifies signature from message details. func verifyDetailsSignature(md *openpgp.MessageDetails, verifierKey *KeyRing, verificationContext *VerificationContext) error { if !md.IsSigned { return newSignatureNotSigned() } if md.SignedBy == nil || len(verifierKey.entities) == 0 || len(verifierKey.entities.KeysById(md.SignedByKeyId)) == 0 { return newSignatureNoVerifier() } if md.SignatureError != nil { return newSignatureFailed(md.SignatureError) } if md.Signature == nil || md.Signature.Hash < allowedHashes[0] || md.Signature.Hash > allowedHashes[len(allowedHashes)-1] { return newSignatureInsecure() } if verificationContext != nil { err := verificationContext.verifyContext(md.Signature) if err != nil { return newSignatureBadContext(err) } } return 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 { 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 } // verifySignature verifies if a signature is valid with the entity list. func verifySignature( pubKeyEntries openpgp.EntityList, origText io.Reader, signature []byte, verifyTime int64, verificationContext *VerificationContext, ) (*packet.Signature, error) { config := &packet.Config{} if verifyTime == 0 { config.Time = func() time.Time { return time.Unix(0, 0) } } else { config.Time = func() time.Time { return time.Unix(verifyTime+internal.CreationTimeOffset, 0) } } if verificationContext != nil { config.KnownNotations = map[string]bool{constants.SignatureContextName: true} } signatureReader := bytes.NewReader(signature) sig, signer, err := openpgp.VerifyDetachedSignatureAndHash(pubKeyEntries, origText, signatureReader, allowedHashes, config) if sig != nil && signer != nil && (errors.Is(err, pgpErrors.ErrSignatureExpired) || errors.Is(err, pgpErrors.ErrKeyExpired)) { //nolint:nestif if verifyTime == 0 { // Expiration check disabled err = nil } else { // Maybe the creation time offset pushed it over the edge // Retry with the actual verification time config.Time = func() time.Time { return time.Unix(verifyTime, 0) } seeker, ok := origText.(io.ReadSeeker) if !ok { return nil, errors.Wrap(err, "gopenpgp: message reader do not support seeking, cannot retry signature verification") } _, err = seeker.Seek(0, io.SeekStart) if err != nil { return nil, newSignatureFailed(errors.Wrap(err, "gopenpgp: could not rewind the data reader.")) } _, err = signatureReader.Seek(0, io.SeekStart) if err != nil { return nil, newSignatureFailed(err) } sig, signer, err = openpgp.VerifyDetachedSignatureAndHash(pubKeyEntries, seeker, signatureReader, allowedHashes, config) } } if err != nil { return nil, newSignatureFailed(err) } if sig == nil || signer == nil { return nil, newSignatureFailed(errors.New("gopenpgp: no signer or valid signature")) } if verificationContext != nil { err := verificationContext.verifyContext(sig) if err != nil { return nil, newSignatureBadContext(err) } } return sig, nil } func signMessageDetached( signKeyRing *KeyRing, messageReader io.Reader, isBinary bool, context *SigningContext, ) (*PGPSignature, error) { config := &packet.Config{ DefaultHash: crypto.SHA512, Time: getTimeGenerator(), } signEntity, err := signKeyRing.getSigningEntity() if err != nil { return nil, err } if context != nil { config.SignatureNotations = append(config.SignatureNotations, context.getNotation()) } var outBuf bytes.Buffer if isBinary { err = openpgp.DetachSign(&outBuf, signEntity, messageReader, config) } else { err = openpgp.DetachSignText(&outBuf, signEntity, messageReader, config) } if err != nil { return nil, errors.Wrap(err, "gopenpgp: error in signing") } return NewPGPSignature(outBuf.Bytes()), nil } golang-github-protonmail-gopenpgp-2.8.1/crypto/signature_collector.go000066400000000000000000000066571472137343600262160ustar00rootroot00000000000000package crypto import ( "bytes" "io" "io/ioutil" "mime" "net/textproto" pgpErrors "github.com/ProtonMail/go-crypto/openpgp/errors" "github.com/ProtonMail/gopenpgp/v2/internal" "github.com/ProtonMail/go-crypto/openpgp" "github.com/ProtonMail/go-crypto/openpgp/packet" gomime "github.com/ProtonMail/go-mime" "github.com/pkg/errors" ) // SignatureCollector structure. type SignatureCollector struct { config *packet.Config keyring openpgp.KeyRing target gomime.VisitAcceptor signature string verified error } func newSignatureCollector( targetAcceptor gomime.VisitAcceptor, keyring openpgp.KeyRing, config *packet.Config, ) *SignatureCollector { return &SignatureCollector{ target: targetAcceptor, config: config, keyring: keyring, } } // 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 } 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 = ioutil.ReadAll(rawBody); err != nil { return errors.Wrap(err, "gopenpgp: 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 } } return } // actual multipart/signed format err = sc.target.Accept(multiparts[0], multipartHeaders[0], hasPlainChild, true, true) if err != nil { return errors.Wrap(err, "gopenpgp: error in parsing body") } partData, err := ioutil.ReadAll(multiparts[1]) if err != nil { return errors.Wrap(err, "gopenpgp: error in ready part data") } decodedPart := gomime.DecodeContentEncoding( bytes.NewReader(partData), multipartHeaders[1].Get("Content-Transfer-Encoding")) buffer, err := ioutil.ReadAll(decodedPart) if err != nil { return errors.Wrap(err, "gopenpgp: 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, "gopenpgp: error in decoding charset") } sc.signature = string(buffer) str, _ := ioutil.ReadAll(rawBody) canonicalizedBody := internal.Canonicalize(internal.TrimEachLine(string(str))) rawBody = bytes.NewReader([]byte(canonicalizedBody)) if sc.keyring != nil { _, err = openpgp.CheckArmoredDetachedSignature(sc.keyring, rawBody, bytes.NewReader(buffer), sc.config) switch { case err == nil: sc.verified = nil case errors.Is(err, pgpErrors.ErrUnknownIssuer): sc.verified = newSignatureNoVerifier() default: sc.verified = newSignatureFailed(err) } } else { sc.verified = newSignatureNoVerifier() } return nil } // GetSignature collected by Accept. func (sc SignatureCollector) GetSignature() string { return sc.signature } golang-github-protonmail-gopenpgp-2.8.1/crypto/signature_test.go000066400000000000000000000414171472137343600252000ustar00rootroot00000000000000package crypto import ( "bytes" "crypto" "errors" "io" "io/ioutil" "regexp" "testing" "time" "github.com/ProtonMail/go-crypto/openpgp" "github.com/ProtonMail/go-crypto/openpgp/packet" "github.com/stretchr/testify/assert" "github.com/ProtonMail/gopenpgp/v2/constants" ) const testMessage = "Hello world!" const signedPlainText = "Signed message\n" var textSignature, binSignature *PGPSignature var message *PlainMessage var signatureTest = regexp.MustCompile("(?s)^-----BEGIN PGP SIGNATURE-----.*-----END PGP SIGNATURE-----$") func getSignatureType(sig *PGPSignature) (packet.SignatureType, error) { sigPacket, err := getSignaturePacket(sig) if err != nil { return 0, err } return sigPacket.SigType, nil } func getSignaturePacket(sig *PGPSignature) (*packet.Signature, error) { p, err := packet.Read(bytes.NewReader(sig.Data)) if err != nil { return nil, err } sigPacket, ok := p.(*packet.Signature) if !ok { return nil, errors.New("") } return sigPacket, nil } func TestSignTextDetached(t *testing.T) { var err error message = NewPlainMessageFromString(signedPlainText) textSignature, err = keyRingTestPrivate.SignDetached(message) if err != nil { t.Fatal("Cannot generate signature:", err) } armoredSignature, err := textSignature.GetArmored() 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, armoredSignature) } func TestVerifyTextDetachedSig(t *testing.T) { verificationError := keyRingTestPublic.VerifyDetached(message, textSignature, testTime) if verificationError != nil { t.Fatal("Cannot verify plaintext signature:", verificationError) } } 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 errror: %v", err) } if castedErr.Status != expectedStatus { t.Fatalf("Expected status to be %d got %d", expectedStatus, castedErr.Status) } } func TestVerifyTextDetachedSigWrong(t *testing.T) { fakeMessage := NewPlainMessageFromString("wrong text") verificationError := keyRingTestPublic.VerifyDetached(fakeMessage, textSignature, testTime) checkVerificationError(t, verificationError, constants.SIGNATURE_FAILED) err := &SignatureVerificationError{} _ = errors.As(verificationError, err) assert.Exactly(t, constants.SIGNATURE_FAILED, err.Status) } func TestSignBinDetached(t *testing.T) { var err error message = NewPlainMessage([]byte(signedPlainText)) binSignature, err = keyRingTestPrivate.SignDetached(message) if err != nil { t.Fatal("Cannot generate signature:", err) } armoredSignature, err := binSignature.GetArmored() 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, armoredSignature) } func TestVerifyBinDetachedSig(t *testing.T) { verificationError := keyRingTestPublic.VerifyDetached(message, binSignature, testTime) if verificationError != nil { t.Fatal("Cannot verify binary signature:", verificationError) } } func Test_KeyRing_GetVerifiedSignatureTimestampSuccess(t *testing.T) { message := NewPlainMessageFromString(testMessage) var time int64 = 1600000000 pgp.latestServerTime = time defer func() { pgp.latestServerTime = testTime }() signature, err := keyRingTestPrivate.SignDetached(message) if err != nil { t.Errorf("Got an error while generating the signature: %v", err) } actualTime, err := keyRingTestPublic.GetVerifiedSignatureTimestamp(message, signature, 0) if err != nil { t.Errorf("Got an error while parsing the signature creation time: %v", err) } if time != actualTime { t.Errorf("Expected creation time to be %d, got %d", time, actualTime) } } func Test_KeyRing_GetVerifiedSignatureTimestampWithContext(t *testing.T) { message := NewPlainMessageFromString(testMessage) var time int64 = 1600000000 pgp.latestServerTime = time defer func() { pgp.latestServerTime = testTime }() var testContext = "test-context" signature, err := keyRingTestPrivate.SignDetachedWithContext(message, NewSigningContext(testContext, true)) if err != nil { t.Errorf("Got an error while generating the signature: %v", err) } actualTime, err := keyRingTestPublic.GetVerifiedSignatureTimestampWithContext(message, signature, 0, NewVerificationContext(testContext, true, 0)) if err != nil { t.Errorf("Got an error while parsing the signature creation time: %v", err) } if time != actualTime { t.Errorf("Expected creation time to be %d, got %d", time, actualTime) } } func Test_KeyRing_GetVerifiedSignatureWithTwoKeysTimestampSuccess(t *testing.T) { publicKey1Armored, err := ioutil.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 := ioutil.ReadFile("testdata/signature/publicKey2") if err != nil { t.Errorf("Couldn't read the public key file: %v", err) } publicKey2 := parseKey(t, string(publicKey2Armored)) message := NewPlainMessageFromString("hello world") signatureArmored, err := ioutil.ReadFile("testdata/signature/detachedSigSignedTwice") if err != nil { t.Errorf("Couldn't read the signature file: %v", err) } signature, err := NewPGPSignatureFromArmored(string(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) } actualTime, err := keyRing.GetVerifiedSignatureTimestamp(message, signature, 0) if err != nil { t.Errorf("Got an error while parsing the signature creation time: %v", err) } if time1 != actualTime { t.Errorf("Expected creation time to be %d, got %d", time1, actualTime) } if time2 == actualTime { t.Errorf("Expected creation time to be different from %d", time2) } } 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 *PGPSignature, keyID uint64) int64 { packets := packet.NewReader(bytes.NewReader(signature.Data)) 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 := NewPlainMessageFromString(testMessage) var time int64 = 1600000000 pgp.latestServerTime = time defer func() { pgp.latestServerTime = testTime }() signature, err := keyRingTestPrivate.SignDetached(message) if err != nil { t.Errorf("Got an error while generating the signature: %v", err) } messageCorrupted := NewPlainMessageFromString("Ciao world!") _, err = keyRingTestPublic.GetVerifiedSignatureTimestamp(messageCorrupted, signature, 0) if err == 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, ) // when signature, err := keyRingTestPrivate.SignDetachedWithContext( NewPlainMessage([]byte(testMessage)), context, ) // then if err != nil { t.Fatal(err) } p, err := packet.Read(bytes.NewReader(signature.Data)) 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, ) // when signature, err := keyRingTestPrivate.SignDetachedWithContext( NewPlainMessage([]byte(testMessage)), context, ) // then if err != nil { t.Fatal(err) } p, err := packet.Read(bytes.NewReader(signature.Data)) 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_VerifyDetachedWithUnknownCriticalContext(t *testing.T) { // given signatureArmored, err := ioutil.ReadFile("testdata/signature/critical_context_detached_sig") if err != nil { t.Fatal(err) } sig, err := NewPGPSignatureFromArmored(string(signatureArmored)) if err != nil { t.Fatal(err) } // when err = keyRingTestPublic.VerifyDetached( NewPlainMessage([]byte(testMessage)), sig, 0, ) // then checkVerificationError(t, err, constants.SIGNATURE_FAILED) } func Test_VerifyDetachedWithUnKnownNonCriticalContext(t *testing.T) { // given signatureArmored, err := ioutil.ReadFile("testdata/signature/non_critical_context_detached_sig") if err != nil { t.Fatal(err) } sig, err := NewPGPSignatureFromArmored(string(signatureArmored)) if err != nil { t.Fatal(err) } // when err = keyRingTestPublic.VerifyDetached( NewPlainMessage([]byte(testMessage)), sig, 0, ) // then if err != nil { t.Fatalf("Expected no verification error, got %v", err) } } func Test_VerifyDetachedWithKnownCriticalContext(t *testing.T) { // given signatureArmored, err := ioutil.ReadFile("testdata/signature/critical_context_detached_sig") if err != nil { t.Fatal(err) } sig, err := NewPGPSignatureFromArmored(string(signatureArmored)) if err != nil { t.Fatal(err) } verificationContext := NewVerificationContext( "test-context", false, 0, ) // when err = keyRingTestPublic.VerifyDetachedWithContext( NewPlainMessage([]byte(testMessage)), sig, 0, verificationContext, ) // then if err != nil { t.Fatalf("Expected no verification error, got %v", err) } } func Test_VerifyDetachedWithWrongContext(t *testing.T) { // given signatureArmored, err := ioutil.ReadFile("testdata/signature/critical_context_detached_sig") if err != nil { t.Fatal(err) } sig, err := NewPGPSignatureFromArmored(string(signatureArmored)) if err != nil { t.Fatal(err) } verificationContext := NewVerificationContext( "another-test-context", false, 0, ) // when err = keyRingTestPublic.VerifyDetachedWithContext( NewPlainMessage([]byte(testMessage)), sig, 0, verificationContext, ) // then checkVerificationError(t, err, constants.SIGNATURE_BAD_CONTEXT) } func Test_VerifyDetachedWithMissingNonRequiredContext(t *testing.T) { // given signatureArmored, err := ioutil.ReadFile("testdata/signature/no_context_detached_sig") if err != nil { t.Fatal(err) } sig, err := NewPGPSignatureFromArmored(string(signatureArmored)) if err != nil { t.Fatal(err) } verificationContext := NewVerificationContext( "test-context", false, 0, ) // when err = keyRingTestPublic.VerifyDetachedWithContext( NewPlainMessage([]byte(testMessage)), sig, 0, verificationContext, ) // then if err != nil { t.Fatalf("Expected no verification error, got %v", err) } } func Test_VerifyDetachedWithMissingRequiredContext(t *testing.T) { // given signatureArmored, err := ioutil.ReadFile("testdata/signature/no_context_detached_sig") if err != nil { t.Fatal(err) } sig, err := NewPGPSignatureFromArmored(string(signatureArmored)) if err != nil { t.Fatal(err) } verificationContext := NewVerificationContext( "test-context", true, 0, ) // when err = keyRingTestPublic.VerifyDetachedWithContext( NewPlainMessage([]byte(testMessage)), sig, 0, verificationContext, ) // then checkVerificationError(t, err, constants.SIGNATURE_BAD_CONTEXT) } func Test_VerifyDetachedWithMissingRequiredContextBeforeCutoff(t *testing.T) { // given signatureArmored, err := ioutil.ReadFile("testdata/signature/no_context_detached_sig") if err != nil { t.Fatal(err) } sig, err := NewPGPSignatureFromArmored(string(signatureArmored)) if err != nil { t.Fatal(err) } p, err := packet.Read(bytes.NewReader(sig.Data)) 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 err = keyRingTestPublic.VerifyDetachedWithContext( NewPlainMessage([]byte(testMessage)), sig, 0, verificationContext, ) // then if err != nil { t.Fatalf("Expected no verification error, got %v", err) } } func Test_VerifyDetachedWithMissingRequiredContextAfterCutoff(t *testing.T) { // given signatureArmored, err := ioutil.ReadFile("testdata/signature/no_context_detached_sig") if err != nil { t.Fatal(err) } sig, err := NewPGPSignatureFromArmored(string(signatureArmored)) if err != nil { t.Fatal(err) } p, err := packet.Read(bytes.NewReader(sig.Data)) 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 err = keyRingTestPublic.VerifyDetachedWithContext( NewPlainMessage([]byte(testMessage)), sig, 0, verificationContext, ) // then checkVerificationError(t, err, constants.SIGNATURE_BAD_CONTEXT) } func Test_VerifyDetachedWithDoubleContext(t *testing.T) { // given signatureArmored, err := ioutil.ReadFile("testdata/signature/double_critical_context_detached_sig") if err != nil { t.Fatal(err) } sig, err := NewPGPSignatureFromArmored(string(signatureArmored)) if err != nil { t.Fatal(err) } verificationContext := NewVerificationContext( "test-context", true, 0, ) // when err = keyRingTestPublic.VerifyDetachedWithContext( NewPlainMessage([]byte(testMessage)), sig, 0, verificationContext, ) // then checkVerificationError(t, err, constants.SIGNATURE_BAD_CONTEXT) } func Test_verifySignaturExpire(t *testing.T) { defer func(t int64) { pgp.latestServerTime = t }(pgp.latestServerTime) pgp.latestServerTime = 0 const lifetime = uint32(time.Hour / time.Second) cfg := &packet.Config{ Algorithm: packet.PubKeyAlgoEdDSA, DefaultHash: crypto.SHA256, DefaultCipher: packet.CipherAES256, DefaultCompressionAlgo: packet.CompressionZLIB, KeyLifetimeSecs: lifetime, SigLifetimeSecs: lifetime, } entity, err := openpgp.NewEntity("John Smith", "Linux", "john.smith@example.com", cfg) if err != nil { t.Fatal(err) } key, err := NewKeyFromEntity(entity) if err != nil { t.Fatal(err) } keyRing, err := NewKeyRing(key) if err != nil { t.Fatal(err) } data := []byte("Hello, World!") message := NewPlainMessage(data) signature, err := keyRing.SignDetached(message) if err != nil { t.Fatalf("%#+v", err) } sig := NewPGPSignature(signature.GetBinary()) // packet.PublicKey.KeyExpired will return false here because PublicKey CreationTime has // nanosecond precision, while pgpcrypto.GetUnixTime() has only second precision. // Adjust the check time to be in the future to ensure that the key is not expired. err = keyRing.VerifyDetached(message, sig, GetUnixTime()+1) if err != nil { t.Fatal(err) } } golang-github-protonmail-gopenpgp-2.8.1/crypto/testdata/000077500000000000000000000000001472137343600234135ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-2.8.1/crypto/testdata/att_body000066400000000000000000000261601472137343600251500ustar00rootroot000000000000000v8AACFOAU9M0+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-2.8.1/crypto/testdata/att_cleartext000066400000000000000000000124071472137343600262050ustar00rootroot00000000000000Lorem 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-2.8.1/crypto/testdata/att_key000066400000000000000000000070271472137343600250040ustar00rootroot00000000000000-----BEGIN PGP PRIVATE KEY BLOCK----- Version: ProtonMail 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 VzFZnZqUR/gGwtdUAkPTcIEe8g== =QGmw -----END PGP PRIVATE KEY BLOCK----- golang-github-protonmail-gopenpgp-2.8.1/crypto/testdata/att_keypacket000066400000000000000000000005541472137343600261720ustar00rootroot00000000000000wcBMA3NHBIPxZtwdAQf/UTdLZjutQTMFLGhlVazAuBHsIG27zFspkSTTDUtQEzeorOggZX4Kj4xOw0AXOe7n2NhOQzc6td7HkjZf8/+eJP1F+njqvmxy+6wCMBU4wDQ1oQR8YidThIdxdhDjmAtTE24ub0R2N2/ENCAAn1bDg+CACnhFN4AJbtvQA9SzDGjur5AS/G9nieuxE6Br6i2QjLFvGoqvXObmHLApiB22vwcpiGEEzYh3ChO+KLGARCUw2eFtyycF8MqIw9mnN2rTN+jOoHF9lEsxRzHr7Dc47dkPsDlqZYEDZzQ2GG97jZDaMceLW/p5OZk/6ffKJAwgHjgs8p2AOMUglFakezjttA==golang-github-protonmail-gopenpgp-2.8.1/crypto/testdata/attachment_keypacket000066400000000000000000000005551472137343600275330ustar00rootroot00000000000000wcBMA0fcZ7XLgmf2AQgAiRsOlnm1kSB4/lr7tYe6pBsRGn10GqwUhrwU5PMKOHdCgnO12jO3y3CzP0Yl/jGhAYja9wLDqH8X0sk3tY32u4Sb1Qe5IuzggAiCa4dwOJj5gEFMTHMzjIMPHR7A70XqUxMhmILye8V4KRm/j4c1sxbzA1rM3lYBumQuB5l/ck0Kgt4ZqxHVXHK5Q1l65FHhSXRj8qnunasHa30TYNzP8nmBA8BinnJxpiQ7FGc2umnUhgkFtjm5ixu9vyjr9ukwDTbwAXXfmY+o7tK7kqIXJcmTL6k2UeC6Mz1AagQtRCRtU+bv/3zGojq/trZo9lom3naIeQYa36Ketmcpj2Qwjg== golang-github-protonmail-gopenpgp-2.8.1/crypto/testdata/gpg2.3-aead-pgp-message.pgp000066400000000000000000000003001472137343600302120ustar00rootroot00000000000000^Y7p}@MMRtɑݖ9 #0%;׬j4# RsRAZA"Ĩ?f/L] eѣ^ kE8^ς8&x#2nQ sAСB6ِj~j1%i6s+-I`pgolang-github-protonmail-gopenpgp-2.8.1/crypto/testdata/gpg2.3-aead-test-key.asc000066400000000000000000000016021472137343600275350ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/issue11_message000066400000000000000000000016471472137343600263440ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/issue11_privatekey000066400000000000000000000070641472137343600271020ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/issue11_publickey000066400000000000000000000032141472137343600266770ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/key_dummy000066400000000000000000000052161472137343600253450ustar00rootroot00000000000000-----BEGIN PGP PRIVATE KEY BLOCK----- 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 XGP4suk8zJsKrEscczTb =HRg1 -----END PGP PRIVATE KEY BLOCK----- golang-github-protonmail-gopenpgp-2.8.1/crypto/testdata/key_expiredKey000066400000000000000000000011461472137343600263210ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/key_futureKey000066400000000000000000000061401472137343600261720ustar00rootroot00000000000000-----BEGIN PGP PRIVATE KEY BLOCK----- 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 0uyeibPdgJTjARMuQzDFA8bdbM540vBf5Q== =WLIN -----END PGP PRIVATE KEY BLOCK----- golang-github-protonmail-gopenpgp-2.8.1/crypto/testdata/key_mismatching_eddsa_key000066400000000000000000000015131472137343600305210ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/key_revoked000066400000000000000000000045131472137343600256500ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/keyring_privateKey000066400000000000000000000070071472137343600272150ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/keyring_privateKeyLegacy000066400000000000000000000070071472137343600303420ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/keyring_publicKey000066400000000000000000000032421472137343600270160ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/keyring_token000066400000000000000000000011531472137343600262060ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/keyring_userKey000066400000000000000000000066741472137343600265320ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/message_badmdc000066400000000000000000000013031472137343600262510ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/message_expired000066400000000000000000000016651472137343600265120ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/message_mixedPasswordPublic000066400000000000000000000033461472137343600310400ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/message_mixedPasswordPublicExpected000066400000000000000000000010411472137343600325100ustar00rootroot00000000000000"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-2.8.1/crypto/testdata/message_sha1_signed000066400000000000000000000023571472137343600272360ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/message_sha256_signed000066400000000000000000000023571472137343600274120ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/message_signed000066400000000000000000000017561472137343600263240ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/mime/000077500000000000000000000000001472137343600243425ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-2.8.1/crypto/testdata/mime/decryption-key.asc000066400000000000000000000016371472137343600300070ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/mime/scenario_00.asc000066400000000000000000000042431472137343600271370ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/mime/scenario_01.asc000066400000000000000000000022131472137343600271330ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/mime/scenario_02.asc000066400000000000000000000042431472137343600271410ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: GopenPGP 2.4.5 Comment: https://gopenpgp.org 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 BJiF4ywh+5vsIxt9 =i2Op -----END PGP MESSAGE-----golang-github-protonmail-gopenpgp-2.8.1/crypto/testdata/mime/scenario_03.asc000066400000000000000000000042431472137343600271420ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/mime/scenario_10.asc000066400000000000000000000037601472137343600271430ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/mime/scenario_11.asc000066400000000000000000000017241472137343600271420ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/mime/scenario_12.asc000066400000000000000000000037601472137343600271450ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/mime/scenario_13.asc000066400000000000000000000037601472137343600271460ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/mime/scenario_20.asc000066400000000000000000000042431472137343600271410ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: GopenPGP 2.4.5 Comment: https://gopenpgp.org wV4DuoHa5jmSStQSAQdAiMnpfLLZjY8QE+e+5HL8ulmge/Xvd1YJIzESwCioOl0w +OusEaYl9IvA2+G33WQ8u3m3ByxQF2Ln1Xp+wwiRbGo+W2ym27Cuq+vR1gexZqJ1 0uoBRLMY9Qy+Nm7w+qg/SWRjndvjeEb3uTjHy3oQHVzaMif77DsksNclVUOW4NhL axuP9ddX1ueTJK9+nivCvT3gFZEG4lpUEhVREKKODpAiMzd17/tuVi2zFBAKC0KU mzn5kW5XpuHB7HykBGpWQWHaxkfzTCS1tpIJ4TxAwTmcSYN2e31magYCeL9+E7oo 9p12Dzy9fAijHIKOkR6tn2WrvugzZ3+uG65JObkOcLfTGflP1MG9UK9yr1slypWi eYi1FY3FDvANJOro5JXA600to+LBVIq7KzaKdIA0Pq8ikY7dEt6biEtdcG+moYIV P5L8qvO+gJxWtgO5/0uMZKShEg50vwmPaxsQkcsi538ibZlZiKNoTiV0KsODZJUm 0yTdTxNpxvwTn/vAxfMgQbL5QgmA1/IVzRaNcgvm11E17QKR/HXscBLQVT4CL6Zy oTObDG75hdnDagTEOHmJvBg3Dsj2nUcySutfSzBy4wGqD1TXEVP9LdXil4I6a8/c co7fgSvoMADb+KVPiJlGKd7wtTuxqfdWOEd9dbPzaF59KNni0BQ8rf4j4tObnKk9 N95UbzUiJCBc+Z5V0R1YGmWPkwW+SWyfjQ2gm+EXNIrsmQrMHQ/uKRo3Gq07J9CW GWc+GW2t3xGD16/DPaaZdgVOJMidIGg03RkXE/zmdTUaW56XR8eEkMWKvB3HDcUR dtcRvZHwfWtmg1lO4zOfKZNZF0grmyHJanS+VdjxDJz+MrER0HAfqxSsEqbdfgJE oFkV1SEQszk3KM0ToUZb77T9VXPWkqAaC+3FE+FVV0jkSVcGSAyId9JfltjHOk18 zIgKhvzlQRYWfST89PTXo1i544QP9j3NbANdU5prtAxNwnLVv/cF1TPzVEGmqfms sAGf2tOqDmt0o9XXXHXkODc4gfJzQNyx0TDDtwLMDKlx0xSh+skwUqrSgfif66Vm 5OfC4KNDKLmE4Vc3e2jbEhoHUZONM8jtrdJKo2jffFH8QPWzFfaSMwERPWAsXMly M3Vn2rr0DLbYgzzlgCVR8a+B/d60/14dnTIfoM+zDSX5CBpBkv4fwcNJocJcXpHH RV6ZAWqLTtNTfRCMqicfXV1zKthwHKAcNefr9RNEtCNtpbqAQZL6Rocb8ocFdfXS 5+/aeVgakuRND3/SMl2bXuMAwHXF7iK8vvI2Jj/q7RImO2cKMOjW/Cd6XCH+Cu0j YsIzWNesRjVw8+/exNeul46IR6aWJ6rYYkK0l2ZpFuGocDdWx7vBkdETPHn9ki7U x+HVjG96NMUKfXlLqpLeL8OCaz21rRIeCRYJVzfnPsr54sHOlSJ6LDytZOJOAlR3 PhUN0+t9y7M+DXSM3ymrSV+5wOgZjLqWfNexCYozZZPEeJnAXX8of5Nq+vzIn2gG BrN3omBDnWH8umycpVKP8Idbh69TvAnuv+7JuEt7SovIWqbrM/6Cblzg+8XoSsLi 1k0GY0TVBPtf8JCXsxUDaRWdOpdkw3ChoAxSk1zDYIQTU4bZZzxanW0AOKAw7q4v eRO8nSlNrAcLV9RtKY/pyPfF+YpZmSSYSUKir/4gYzKVodQly99W0WH5JQ1pcm3k tDU+2ZJxRSDKxDpx6DNiVABVxGshcsgnxe7tdI4fQ/Ij56pAfqV4bLsPhDvQ9rvH 9T/YaO4pOrimzPndAPBfvNPp4MF5NYILzrF7A5P95Zt3hG1Dw40fHRP591FiLLfO RmCC0X73H1rHLwl9u3Pi66538OG+ke4ZF/YwkBSJdpRQeIb+M3+ISdEQm8KQjY2E LZh6HrqE9oNYvR/SdSit6R9TQQNapbZdcyjv1iBTd3MIj690UQGDH4r6MnFBWUMR gC7ROMV1VtijZWjqevb0V7HgubkYCQmyorzaMVH3dHyFP4VKi878RGv89HaHc/Mj nQPktLH4gY71cI8d =0SK5 -----END PGP MESSAGE-----golang-github-protonmail-gopenpgp-2.8.1/crypto/testdata/mime/scenario_21.asc000066400000000000000000000022131472137343600271350ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/mime/scenario_22.asc000066400000000000000000000042431472137343600271430ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/mime/scenario_23.asc000066400000000000000000000042431472137343600271440ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: GopenPGP 2.4.5 Comment: https://gopenpgp.org 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 fuoVwj3delL/Ndzc =sXg5 -----END PGP MESSAGE-----golang-github-protonmail-gopenpgp-2.8.1/crypto/testdata/mime/verification-key.asc000066400000000000000000000012751472137343600303070ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/mime_decodedBody000066400000000000000000000013331472137343600265520ustar00rootroot00000000000000


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

golang-github-protonmail-gopenpgp-2.8.1/crypto/testdata/mime_decodedBodyHeaders000066400000000000000000000001121472137343600300400ustar00rootroot00000000000000Content-Transfer-Encoding: base64 Content-Type: text/html;charset=utf-8 golang-github-protonmail-gopenpgp-2.8.1/crypto/testdata/mime_decryptedBody000066400000000000000000000005411472137343600271460ustar00rootroot00000000000000Pak > 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-2.8.1/crypto/testdata/mime_pgpMessage000066400000000000000000000061601472137343600264430ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: ProtonMail Comment: https://protonmail.com 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 LloBMV1YNGsW45M+oQ== =BRHT -----END PGP MESSAGE----- golang-github-protonmail-gopenpgp-2.8.1/crypto/testdata/mime_privateKey000066400000000000000000000151711472137343600264750ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/mime_publicKey000066400000000000000000000061071472137343600263000ustar00rootroot00000000000000-----BEGIN PGP PUBLIC KEY BLOCK----- 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 OQTmvM6R =DvFv -----END PGP PUBLIC KEY BLOCK----- golang-github-protonmail-gopenpgp-2.8.1/crypto/testdata/mime_testMessage000066400000000000000000000153101472137343600266310ustar00rootroot00000000000000Content-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-2.8.1/crypto/testdata/sed_key000066400000000000000000000117741472137343600247730ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/sed_message000066400000000000000000000012421472137343600256140ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/sessionkey_key000066400000000000000000000033701472137343600264050ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/sessionkey_packet000066400000000000000000000005541472137343600270650ustar00rootroot00000000000000wcBMAykFqdVSI1GtAQf+ID+pqYcKMsHUeos3qQ/2zJ+8XguKg8/bpW66XXQJOlXO/yWP5NplcuBIZcDfnJ9gk8cpOg8QXCzgk4BqmpuDVrShn0M4UnmcISC43i5L8+tS63Vv0LHxdcj5ADYAFKz0bRKjhf3JFjibttn8nuEEJJVNi4zUwC2lVr8v5THxj6SpZtNrBeFaaQ0Y78q8rNqPZtNqq2TcCmlVj4d+VnNnbkEOrizw97I9P784L169s0kVb3S0t0r1Y/mOPxq3T1EXDbo37quveZjKHgkuT/1FTOEO2yzqPOhyRlF6MuQYlPJMZv9pHwNDCyfm8WQutzpRK+MI4AcqVyALC4rU3w9JNg==golang-github-protonmail-gopenpgp-2.8.1/crypto/testdata/signature/000077500000000000000000000000001472137343600254145ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-2.8.1/crypto/testdata/signature/critical_context_detached_sig000066400000000000000000000011221472137343600333540ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/signature/detachedSigSignedTwice000066400000000000000000000006061472137343600316730ustar00rootroot00000000000000-----BEGIN PGP SIGNATURE----- wnUEARYKAAYFAmCCo8gAIQkQyQtnL+EYbekWIQTopSabUSqDUEv/FMHJC2cv 4Rht6VeGAP4mUJl+WYN9nLE57YByTh95OmcZmwfgz5Z4R570YqTVngD/VBym icc7YREcxij1gC6SSAe8kgKW6oVOWzxJ8HkOSQrCdQQBFgoABgUCYIK9vQAh CRCGHCX3YYW5NRYhBErDPc6OYkUaNQCLhoYcJfdhhbk1W1QBAPhrkAjimO22 jh1V2A8pRCOs53Ig/AMAFbN37BaAIEVKAP0SVMTL6zTxYJcxWNPog7Bv5lM4 Px4G+hZ2Kia//qlgBg== =0aeU -----END PGP SIGNATURE-----double_critical_context_detached_sig000066400000000000000000000012071472137343600346330ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-2.8.1/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-2.8.1/crypto/testdata/signature/no_context_detached_sig000066400000000000000000000010351472137343600322010ustar00rootroot00000000000000-----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-----golang-github-protonmail-gopenpgp-2.8.1/crypto/testdata/signature/non_critical_context_detached_sig000066400000000000000000000011221472137343600342260ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/signature/publicKey1000066400000000000000000000011431472137343600273460ustar00rootroot00000000000000-----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-2.8.1/crypto/testdata/signature/publicKey2000066400000000000000000000011431472137343600273470ustar00rootroot00000000000000-----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-2.8.1/crypto/time.go000066400000000000000000000027161472137343600230750ustar00rootroot00000000000000package crypto import ( "time" ) // UpdateTime updates cached time. func UpdateTime(newTime int64) { pgp.lock.Lock() defer pgp.lock.Unlock() if newTime > pgp.latestServerTime { pgp.latestServerTime = newTime } } // SetKeyGenerationOffset updates the offset when generating keys. func SetKeyGenerationOffset(offset int64) { pgp.lock.Lock() defer pgp.lock.Unlock() pgp.generationOffset = offset } // GetUnixTime gets latest cached time. func GetUnixTime() int64 { return getNow().Unix() } // GetTime gets latest cached time. func GetTime() time.Time { return getNow() } // ----- INTERNAL FUNCTIONS ----- // getNow returns the latest server time. func getNow() time.Time { pgp.lock.RLock() defer pgp.lock.RUnlock() if pgp.latestServerTime == 0 { return time.Now() } return time.Unix(pgp.latestServerTime, 0) } // getTimeGenerator Returns a time generator function. func getTimeGenerator() func() time.Time { return getNow } // getNowKeyGenerationOffset returns the current time with the key generation offset. func getNowKeyGenerationOffset() time.Time { pgp.lock.RLock() defer pgp.lock.RUnlock() if pgp.latestServerTime == 0 { return time.Unix(time.Now().Unix()+pgp.generationOffset, 0) } return time.Unix(pgp.latestServerTime+pgp.generationOffset, 0) } // getKeyGenerationTimeGenerator Returns a time generator function with the key generation offset. func getKeyGenerationTimeGenerator() func() time.Time { return getNowKeyGenerationOffset } golang-github-protonmail-gopenpgp-2.8.1/crypto/time_test.go000066400000000000000000000004351472137343600241300ustar00rootroot00000000000000package crypto import ( "testing" "time" "github.com/stretchr/testify/assert" ) func TestTime(t *testing.T) { UpdateTime(1571072494) time.Sleep(1 * time.Second) now := GetUnixTime() assert.Exactly(t, int64(1571072494), now) // Use latest server time UpdateTime(testTime) } golang-github-protonmail-gopenpgp-2.8.1/go.mod000066400000000000000000000010641472137343600213710ustar00rootroot00000000000000module github.com/ProtonMail/gopenpgp/v2 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 golang.org/x/crypto v0.17.0 ) require ( github.com/cloudflare/circl v1.3.7 // indirect github.com/davecgh/go-spew v1.1.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect golang.org/x/sys v0.16.0 // indirect golang.org/x/text v0.14.0 // indirect gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect ) golang-github-protonmail-gopenpgp-2.8.1/go.sum000066400000000000000000000132641472137343600214230ustar00rootroot00000000000000github.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/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 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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-2.8.1/helper/000077500000000000000000000000001472137343600215415ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-2.8.1/helper/base_test.go000066400000000000000000000011151472137343600240370ustar00rootroot00000000000000package helper import ( "io/ioutil" "strings" "github.com/ProtonMail/gopenpgp/v2/crypto" ) const testTime = 1557754627 // 2019-05-13T13:37:07+00:00 func readTestFile(name string, trimNewlines bool) string { data, err := ioutil.ReadFile("../crypto/testdata/" + name) //nolint if err != nil { panic(err) } if trimNewlines { return strings.TrimRight(string(data), "\n") } return string(data) } // Corresponding key in ../crypto/testdata/keyring_privateKey. var testMailboxPassword = []byte("apple") func init() { crypto.UpdateTime(testTime) // 2019-05-13T13:37:07+00:00 } golang-github-protonmail-gopenpgp-2.8.1/helper/cleartext.go000066400000000000000000000055431472137343600240720ustar00rootroot00000000000000package helper import ( "github.com/ProtonMail/gopenpgp/v2/crypto" "github.com/ProtonMail/gopenpgp/v2/internal" "github.com/pkg/errors" ) // SignCleartextMessageArmored signs text given a private key and its // passphrase, canonicalizes and trims the newlines, and returns the // PGP-compliant special armoring. func SignCleartextMessageArmored(privateKey string, passphrase []byte, text string) (string, error) { signingKey, err := crypto.NewKeyFromArmored(privateKey) if err != nil { return "", errors.Wrap(err, "gopenpgp: error in creating key object") } unlockedKey, err := signingKey.Unlock(passphrase) if err != nil { return "", errors.Wrap(err, "gopenpgp: error in unlocking key") } defer unlockedKey.ClearPrivateParams() keyRing, err := crypto.NewKeyRing(unlockedKey) if err != nil { return "", errors.Wrap(err, "gopenpgp: error in creating keyring") } return SignCleartextMessage(keyRing, text) } // VerifyCleartextMessageArmored verifies PGP-compliant armored signed plain // text given the public key and returns the text or err if the verification // fails. func VerifyCleartextMessageArmored(publicKey, armored string, verifyTime int64) (string, error) { signingKey, err := crypto.NewKeyFromArmored(publicKey) if err != nil { return "", errors.Wrap(err, "gopenpgp: error in creating key object") } verifyKeyRing, err := crypto.NewKeyRing(signingKey) if err != nil { return "", errors.Wrap(err, "gopenpgp: error in creating key ring") } return VerifyCleartextMessage(verifyKeyRing, armored, verifyTime) } // SignCleartextMessage signs text given a private keyring, canonicalizes and // trims the newlines, and returns the PGP-compliant special armoring. func SignCleartextMessage(keyRing *crypto.KeyRing, text string) (string, error) { message := crypto.NewPlainMessageFromString(internal.TrimEachLine(text)) signature, err := keyRing.SignDetached(message) if err != nil { return "", errors.Wrap(err, "gopenpgp: error in signing cleartext message") } return crypto.NewClearTextMessage(message.GetBinary(), signature.GetBinary()).GetArmored() } // VerifyCleartextMessage verifies PGP-compliant armored signed plain text // given the public keyring and returns the text or err if the verification // fails. func VerifyCleartextMessage(keyRing *crypto.KeyRing, armored string, verifyTime int64) (string, error) { clearTextMessage, err := crypto.NewClearTextMessageFromArmored(armored) if err != nil { return "", errors.Wrap(err, "gopengpp: unable to unarmor cleartext message") } message := crypto.NewPlainMessageFromString(internal.TrimEachLine(clearTextMessage.GetString())) signature := crypto.NewPGPSignature(clearTextMessage.GetBinarySignature()) err = keyRing.VerifyDetached(message, signature, verifyTime) if err != nil { return "", errors.Wrap(err, "gopengpp: unable to verify cleartext message") } return message.GetString(), nil } golang-github-protonmail-gopenpgp-2.8.1/helper/cleartext_test.go000066400000000000000000000023261472137343600251250ustar00rootroot00000000000000package helper import ( "regexp" "testing" "github.com/ProtonMail/gopenpgp/v2/internal" "github.com/ProtonMail/gopenpgp/v2/crypto" "github.com/stretchr/testify/assert" ) const inputPlainText = " Signed message\n \n " const signedPlainText = " Signed message\n\n" var signedMessageTest = regexp.MustCompile( "(?s)^-----BEGIN PGP SIGNED MESSAGE-----.*-----BEGIN PGP SIGNATURE-----.*-----END PGP SIGNATURE-----$") func TestSignClearText(t *testing.T) { // Password defined in base_test armored, err := SignCleartextMessageArmored( readTestFile("keyring_privateKey", false), testMailboxPassword, inputPlainText, ) if err != nil { t.Fatal("Cannot armor message:", err) } assert.Regexp(t, signedMessageTest, armored) verified, err := VerifyCleartextMessageArmored( readTestFile("keyring_publicKey", false), armored, crypto.GetUnixTime(), ) if err != nil { t.Fatal("Cannot verify message:", err) } assert.Exactly(t, signedPlainText, verified) clearTextMessage, err := crypto.NewClearTextMessageFromArmored(armored) if err != nil { t.Fatal("Cannot parse message:", err) } assert.Exactly(t, internal.Canonicalize(internal.TrimEachLine(inputPlainText)), string(clearTextMessage.GetBinary())) } golang-github-protonmail-gopenpgp-2.8.1/helper/decrypt_check.go000066400000000000000000000054351472137343600247060ustar00rootroot00000000000000package helper import ( "bytes" "crypto/aes" "crypto/cipher" "io" "github.com/ProtonMail/go-crypto/openpgp/packet" "github.com/ProtonMail/gopenpgp/v2/crypto" "github.com/pkg/errors" ) const AES_BLOCK_SIZE = 16 func supported(cipher packet.CipherFunction) bool { switch cipher { case packet.CipherAES128, packet.CipherAES192, packet.CipherAES256: return true case packet.CipherCAST5, packet.Cipher3DES: return false } return false } func blockSize(cipher packet.CipherFunction) int { switch cipher { case packet.CipherAES128, packet.CipherAES192, packet.CipherAES256: return AES_BLOCK_SIZE case packet.CipherCAST5, packet.Cipher3DES: return 0 } return 0 } func blockCipher(cipher packet.CipherFunction, key []byte) (cipher.Block, error) { switch cipher { case packet.CipherAES128, packet.CipherAES192, packet.CipherAES256: return aes.NewCipher(key) case packet.CipherCAST5, packet.Cipher3DES: return nil, errors.New("gopenpgp: cipher not supported for quick check") } return nil, errors.New("gopenpgp: unknown cipher") } // QuickCheckDecryptReader checks with high probability if the provided session key // can decrypt a data packet given its 24 byte long prefix. // The method reads up to but not exactly 24 bytes from the prefixReader. // NOTE: Only works for SEIPDv1 packets with AES. func QuickCheckDecryptReader(sessionKey *crypto.SessionKey, prefixReader crypto.Reader) (bool, error) { algo, err := sessionKey.GetCipherFunc() if err != nil { return false, errors.New("gopenpgp: cipher algorithm not found") } if !supported(algo) { return false, errors.New("gopenpgp: cipher not supported for quick check") } packetParser := packet.NewReader(prefixReader) _, err = packetParser.Next() if err != nil { return false, errors.New("gopenpgp: failed to parse packet prefix") } blockSize := blockSize(algo) encryptedData := make([]byte, blockSize+2) _, err = io.ReadFull(prefixReader, encryptedData) if err != nil { return false, errors.New("gopenpgp: prefix is too short to check") } blockCipher, err := blockCipher(algo, sessionKey.Key) if err != nil { return false, errors.New("gopenpgp: failed to initialize the cipher") } _ = packet.NewOCFBDecrypter(blockCipher, encryptedData, packet.OCFBNoResync) return encryptedData[blockSize-2] == encryptedData[blockSize] && encryptedData[blockSize-1] == encryptedData[blockSize+1], nil } // QuickCheckDecrypt checks with high probability if the provided session key // can decrypt the encrypted data packet given its 24 byte long prefix. // The method only considers the first 24 bytes of the prefix slice (prefix[:24]). // NOTE: Only works for SEIPDv1 packets with AES. func QuickCheckDecrypt(sessionKey *crypto.SessionKey, prefix []byte) (bool, error) { return QuickCheckDecryptReader(sessionKey, bytes.NewReader(prefix)) } golang-github-protonmail-gopenpgp-2.8.1/helper/decrypt_check_test.go000066400000000000000000000021271472137343600257400ustar00rootroot00000000000000package helper import ( "encoding/hex" "testing" "github.com/ProtonMail/gopenpgp/v2/crypto" ) const testQuickCheckSessionKey = `038c9cb9d408074e36bac22c6b90973082f86e5b01f38b787da3927000365a81` const testQuickCheckSessionKeyAlg = "aes256" const testQuickCheckDataPacket = `d2540152ab2518950f282d98d901eb93c00fb55a3bb30b3b517d6a356f57884bac6963060ebb167ffc3296e5e99ec058aeff5003a4784a0734a62861ae56d2921b9b790d50586cd21cad45e2d84ac93fb5d8af2ce6c5` func TestCheckDecrypt(t *testing.T) { sessionKeyData, err := hex.DecodeString(testQuickCheckSessionKey) if err != nil { t.Error(err) } dataPacket, err := hex.DecodeString(testQuickCheckDataPacket) if err != nil { t.Error(err) } sessionKey := &crypto.SessionKey{ Key: sessionKeyData, Algo: testQuickCheckSessionKeyAlg, } ok, err := QuickCheckDecrypt(sessionKey, dataPacket[:22]) if err != nil { t.Error(err) } if !ok { t.Error("should be able to decrypt") } sessionKey.Key[0] += 1 ok, err = QuickCheckDecrypt(sessionKey, dataPacket[:22]) if err != nil { t.Error(err) } if ok { t.Error("should no be able to decrypt") } } golang-github-protonmail-gopenpgp-2.8.1/helper/helper.go000066400000000000000000000466301472137343600233600ustar00rootroot00000000000000// Package helper contains several functions with a simple interface to extend usability and compatibility with gomobile package helper import ( "github.com/ProtonMail/gopenpgp/v2/crypto" "github.com/pkg/errors" ) // EncryptMessageWithPassword encrypts a string with a passphrase using AES256. func EncryptMessageWithPassword(password []byte, plaintext string) (ciphertext string, err error) { var pgpMessage *crypto.PGPMessage var message = crypto.NewPlainMessageFromString(plaintext) if pgpMessage, err = crypto.EncryptMessageWithPassword(message, password); err != nil { return "", errors.Wrap(err, "gopenpgp: unable to encrypt message with password") } if ciphertext, err = pgpMessage.GetArmored(); err != nil { return "", errors.Wrap(err, "gopenpgp: unable to armor ciphertext") } return ciphertext, nil } // DecryptMessageWithPassword decrypts an armored message with a random token. // The algorithm is derived from the armoring. func DecryptMessageWithPassword(password []byte, ciphertext string) (plaintext string, err error) { var message *crypto.PlainMessage var pgpMessage *crypto.PGPMessage if pgpMessage, err = crypto.NewPGPMessageFromArmored(ciphertext); err != nil { return "", errors.Wrap(err, "gopenpgp: unable to unarmor ciphertext") } if message, err = crypto.DecryptMessageWithPassword(pgpMessage, password); err != nil { return "", errors.Wrap(err, "gopenpgp: unable to decrypt message with password") } return message.GetString(), nil } // EncryptMessageArmored generates an armored PGP message given a plaintext and // an armored public key. func EncryptMessageArmored(key, plaintext string) (string, error) { return encryptMessageArmored(key, crypto.NewPlainMessageFromString(plaintext)) } // EncryptSignMessageArmored generates an armored signed PGP message given a // plaintext and an armored public key a private key and its passphrase. func EncryptSignMessageArmored( publicKey, privateKey string, passphrase []byte, plaintext string, ) (ciphertext string, err error) { var privateKeyObj, unlockedKeyObj *crypto.Key var publicKeyRing, privateKeyRing *crypto.KeyRing var pgpMessage *crypto.PGPMessage var message = crypto.NewPlainMessageFromString(plaintext) if publicKeyRing, err = createPublicKeyRing(publicKey); err != nil { return "", err } if privateKeyObj, err = crypto.NewKeyFromArmored(privateKey); err != nil { return "", errors.Wrap(err, "gopenpgp: unable to read key") } if unlockedKeyObj, err = privateKeyObj.Unlock(passphrase); err != nil { return "", errors.Wrap(err, "gopenpgp: unable to unlock key") } defer unlockedKeyObj.ClearPrivateParams() if privateKeyRing, err = crypto.NewKeyRing(unlockedKeyObj); err != nil { return "", errors.Wrap(err, "gopenpgp: unable to create new keyring") } if pgpMessage, err = publicKeyRing.Encrypt(message, privateKeyRing); err != nil { return "", errors.Wrap(err, "gopenpgp: unable to encrypt message") } if ciphertext, err = pgpMessage.GetArmored(); err != nil { return "", errors.Wrap(err, "gopenpgp: unable to armor ciphertext") } return ciphertext, nil } // DecryptMessageArmored decrypts an armored PGP message given a private key // and its passphrase. func DecryptMessageArmored( privateKey string, passphrase []byte, ciphertext string, ) (string, error) { message, err := decryptMessageArmored(privateKey, passphrase, ciphertext) if err != nil { return "", err } return message.GetString(), nil } // DecryptVerifyMessageArmored decrypts an armored PGP message given a private // key and its passphrase and verifies the embedded signature. Returns the // plain data or an error on signature verification failure. func DecryptVerifyMessageArmored( publicKey, privateKey string, passphrase []byte, ciphertext string, ) (plaintext string, err error) { var privateKeyObj, unlockedKeyObj *crypto.Key var publicKeyRing, privateKeyRing *crypto.KeyRing var pgpMessage *crypto.PGPMessage var message *crypto.PlainMessage if publicKeyRing, err = createPublicKeyRing(publicKey); err != nil { return "", err } if privateKeyObj, err = crypto.NewKeyFromArmored(privateKey); err != nil { return "", errors.Wrap(err, "gopenpgp: unable to unarmor private key") } if unlockedKeyObj, err = privateKeyObj.Unlock(passphrase); err != nil { return "", errors.Wrap(err, "gopenpgp: unable to unlock private key") } defer unlockedKeyObj.ClearPrivateParams() if privateKeyRing, err = crypto.NewKeyRing(unlockedKeyObj); err != nil { return "", errors.Wrap(err, "gopenpgp: unable to create new keyring") } if pgpMessage, err = crypto.NewPGPMessageFromArmored(ciphertext); err != nil { return "", errors.Wrap(err, "gopenpgp: unable to unarmor ciphertext") } if message, err = privateKeyRing.Decrypt(pgpMessage, publicKeyRing, crypto.GetUnixTime()); err != nil { return "", errors.Wrap(err, "gopenpgp: unable to decrypt message") } return message.GetString(), nil } // DecryptVerifyAttachment decrypts and verifies an attachment split into the // keyPacket, dataPacket and an armored (!) signature, given a publicKey, and a // privateKey with its passphrase. Returns the plain data or an error on // signature verification failure. func DecryptVerifyAttachment( publicKey, privateKey string, passphrase, keyPacket, dataPacket []byte, armoredSignature string, ) (plainData []byte, err error) { // We decrypt the attachment message, err := decryptAttachment(privateKey, passphrase, keyPacket, dataPacket) if err != nil { return nil, err } // We verify the signature var check bool if check, err = verifyDetachedArmored(publicKey, message, armoredSignature); err != nil { return nil, err } if !check { return nil, errors.New("gopenpgp: unable to verify attachment") } return message.GetBinary(), nil } // EncryptBinaryMessageArmored generates an armored PGP message given a binary data and // an armored public key. func EncryptBinaryMessageArmored(key string, data []byte) (string, error) { return encryptMessageArmored(key, crypto.NewPlainMessage(data)) } // DecryptBinaryMessageArmored decrypts an armored PGP message given a private key // and its passphrase. func DecryptBinaryMessageArmored(privateKey string, passphrase []byte, ciphertext string) ([]byte, error) { message, err := decryptMessageArmored(privateKey, passphrase, ciphertext) if err != nil { return nil, err } return message.GetBinary(), nil } // encryptSignArmoredDetached takes a public key for encryption, // a private key and its passphrase for signature, and the plaintext data // Returns an armored ciphertext and a detached armored encrypted signature. func encryptSignArmoredDetached( publicKey, privateKey string, passphrase, plainData []byte, ) (ciphertextArmored, encryptedSignatureArmored string, err error) { var message = crypto.NewPlainMessage(plainData) // We encrypt and signcrypt ciphertext, encryptedSignatureArmored, err := encryptSignObjDetached(publicKey, privateKey, passphrase, message) if err != nil { return "", "", err } // We armor the ciphertext and signature ciphertextArmored, err = ciphertext.GetArmored() if err != nil { return "", "", errors.Wrap(err, "gopenpgp: unable to armor the ciphertext") } return ciphertextArmored, encryptedSignatureArmored, nil } // DecryptVerifyArmoredDetached decrypts an armored pgp message // and verify a detached armored encrypted signature // given a publicKey, and a privateKey with its passphrase. // Returns the plain data or an error on // signature verification failure. func DecryptVerifyArmoredDetached( publicKey, privateKey string, passphrase []byte, ciphertextArmored string, encryptedSignatureArmored string, ) (plainData []byte, err error) { // Some type casting ciphertext, err := crypto.NewPGPMessageFromArmored(ciphertextArmored) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to unarmor ciphertext") } // We decrypt and verify the encrypted signature message, err := decryptVerifyObjDetached(publicKey, privateKey, passphrase, ciphertext, encryptedSignatureArmored) if err != nil { return nil, err } return message.GetBinary(), nil } // encryptSignBinaryDetached takes a public key for encryption, // a private key and its passphrase for signature, and the plaintext data // Returns encrypted binary data and a detached armored encrypted signature. func encryptSignBinaryDetached( publicKey, privateKey string, passphrase, plainData []byte, ) (encryptedData []byte, encryptedSignatureArmored string, err error) { // Some type casting message := crypto.NewPlainMessage(plainData) // We encrypt and signcrypt ciphertext, encryptedSignatureArmored, err := encryptSignObjDetached(publicKey, privateKey, passphrase, message) if err != nil { return nil, "", err } // We get the encrypted data encryptedData = ciphertext.GetBinary() return encryptedData, encryptedSignatureArmored, nil } // DecryptVerifyBinaryDetached decrypts binary encrypted data // and verify a detached armored encrypted signature // given a publicKey, and a privateKey with its passphrase. // Returns the plain data or an error on // signature verification failure. func DecryptVerifyBinaryDetached( publicKey, privateKey string, passphrase []byte, encryptedData []byte, encryptedSignatureArmored string, ) (plainData []byte, err error) { // Some type casting ciphertext := crypto.NewPGPMessage(encryptedData) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to parse ciphertext") } // We decrypt and verify the encrypted signature message, err := decryptVerifyObjDetached(publicKey, privateKey, passphrase, ciphertext, encryptedSignatureArmored) if err != nil { return nil, err } return message.GetBinary(), nil } // EncryptAttachmentWithKey encrypts a binary file // Using a given armored public key. func EncryptAttachmentWithKey( publicKey string, filename string, plainData []byte, ) (message *crypto.PGPSplitMessage, err error) { publicKeyRing, err := createPublicKeyRing(publicKey) if err != nil { return nil, err } return EncryptAttachment(plainData, filename, publicKeyRing) } // DecryptAttachmentWithKey decrypts a binary file // Using a given armored private key and its passphrase. func DecryptAttachmentWithKey( privateKey string, passphrase, keyPacket, dataPacket []byte, ) (attachment []byte, err error) { message, err := decryptAttachment(privateKey, passphrase, keyPacket, dataPacket) if err != nil { return nil, err } return message.GetBinary(), nil } // EncryptSessionKey encrypts a session key // using a given armored public key. func EncryptSessionKey( publicKey string, sessionKey *crypto.SessionKey, ) (encryptedSessionKey []byte, err error) { publicKeyRing, err := createPublicKeyRing(publicKey) if err != nil { return nil, err } encryptedSessionKey, err = publicKeyRing.EncryptSessionKey(sessionKey) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to encrypt sessionKey") } return encryptedSessionKey, nil } // DecryptSessionKey decrypts a session key // using a given armored private key // and its passphrase. func DecryptSessionKey( privateKey string, passphrase, encryptedSessionKey []byte, ) (sessionKey *crypto.SessionKey, err error) { privateKeyObj, err := crypto.NewKeyFromArmored(privateKey) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to read armored key") } privateKeyUnlocked, err := privateKeyObj.Unlock(passphrase) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to unlock private key") } defer privateKeyUnlocked.ClearPrivateParams() privateKeyRing, err := crypto.NewKeyRing(privateKeyUnlocked) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to create new keyring") } sessionKey, err = privateKeyRing.DecryptSessionKey(encryptedSessionKey) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to decrypt session key") } return sessionKey, nil } func encryptMessageArmored(key string, message *crypto.PlainMessage) (string, error) { ciphertext, err := encryptMessage(key, message) if err != nil { return "", err } ciphertextArmored, err := ciphertext.GetArmored() if err != nil { return "", errors.Wrap(err, "gopenpgp: unable to armor ciphertext") } return ciphertextArmored, nil } func decryptMessageArmored(privateKey string, passphrase []byte, ciphertextArmored string) (*crypto.PlainMessage, error) { ciphertext, err := crypto.NewPGPMessageFromArmored(ciphertextArmored) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to parse ciphertext") } return decryptMessage(privateKey, passphrase, ciphertext) } func encryptMessage(key string, message *crypto.PlainMessage) (*crypto.PGPMessage, error) { publicKeyRing, err := createPublicKeyRing(key) if err != nil { return nil, err } ciphertext, err := publicKeyRing.Encrypt(message, nil) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to encrypt message") } return ciphertext, nil } func decryptMessage(privateKey string, passphrase []byte, ciphertext *crypto.PGPMessage) (*crypto.PlainMessage, error) { privateKeyObj, err := crypto.NewKeyFromArmored(privateKey) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to parse the private key") } privateKeyUnlocked, err := privateKeyObj.Unlock(passphrase) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to unlock key") } defer privateKeyUnlocked.ClearPrivateParams() privateKeyRing, err := crypto.NewKeyRing(privateKeyUnlocked) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to create the private key ring") } message, err := privateKeyRing.Decrypt(ciphertext, nil, 0) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to decrypt message") } return message, nil } func signDetached(privateKey string, passphrase []byte, message *crypto.PlainMessage) (detachedSignature *crypto.PGPSignature, err error) { privateKeyObj, err := crypto.NewKeyFromArmored(privateKey) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to parse private key") } privateKeyUnlocked, err := privateKeyObj.Unlock(passphrase) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to unlock key") } defer privateKeyUnlocked.ClearPrivateParams() privateKeyRing, err := crypto.NewKeyRing(privateKeyUnlocked) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to create new keyring") } detachedSignature, err = privateKeyRing.SignDetached(message) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to sign message") } return detachedSignature, nil } func verifyDetachedArmored(publicKey string, message *crypto.PlainMessage, armoredSignature string) (check bool, err error) { var detachedSignature *crypto.PGPSignature // We unarmor the signature if detachedSignature, err = crypto.NewPGPSignatureFromArmored(armoredSignature); err != nil { return false, errors.Wrap(err, "gopenpgp: unable to unarmor signature") } // we verify the signature return verifyDetached(publicKey, message, detachedSignature) } func verifyDetached(publicKey string, message *crypto.PlainMessage, detachedSignature *crypto.PGPSignature) (check bool, err error) { var publicKeyRing *crypto.KeyRing // We prepare the public key for signature verification publicKeyRing, err = createPublicKeyRing(publicKey) if err != nil { return false, err } // We verify the signature if publicKeyRing.VerifyDetached(message, detachedSignature, crypto.GetUnixTime()) != nil { return false, nil } return true, nil } func decryptAttachment( privateKey string, passphrase, keyPacket, dataPacket []byte, ) (message *crypto.PlainMessage, err error) { var privateKeyObj, unlockedKeyObj *crypto.Key var privateKeyRing *crypto.KeyRing packets := crypto.NewPGPSplitMessage(keyPacket, dataPacket) // prepare the private key for decryption if privateKeyObj, err = crypto.NewKeyFromArmored(privateKey); err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to parse private key") } if unlockedKeyObj, err = privateKeyObj.Unlock(passphrase); err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to unlock private key") } defer unlockedKeyObj.ClearPrivateParams() if privateKeyRing, err = crypto.NewKeyRing(unlockedKeyObj); err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to create new keyring") } if message, err = privateKeyRing.DecryptAttachment(packets); err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to decrypt attachment") } return message, nil } func createPublicKeyRing(publicKey string) (*crypto.KeyRing, error) { publicKeyObj, err := crypto.NewKeyFromArmored(publicKey) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to parse public key") } if publicKeyObj.IsPrivate() { publicKeyObj, err = publicKeyObj.ToPublic() if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to extract public key from private key") } } publicKeyRing, err := crypto.NewKeyRing(publicKeyObj) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to create new keyring") } return publicKeyRing, nil } func encryptSignObjDetached( publicKey, privateKey string, passphrase []byte, message *crypto.PlainMessage, ) (ciphertext *crypto.PGPSplitMessage, encryptedSignatureArmored string, err error) { // We generate the session key sessionKey, err := crypto.GenerateSessionKey() if err != nil { return nil, "", errors.Wrap(err, "gopenpgp: unable to create new session key") } // We encrypt the message with the session key messageDataPacket, err := sessionKey.Encrypt(message) if err != nil { return nil, "", errors.Wrap(err, "gopenpgp: unable to encrypt message") } // We sign the message detachedSignature, err := signDetached(privateKey, passphrase, message) if err != nil { return nil, "", errors.Wrap(err, "gopenpgp: unable to sign message") } // We encrypt the signature with the session key signaturePlaintext := crypto.NewPlainMessage(detachedSignature.GetBinary()) signatureDataPacket, err := sessionKey.Encrypt(signaturePlaintext) if err != nil { return nil, "", errors.Wrap(err, "gopenpgp: unable to encrypt detached signature") } // We encrypt the session key keyPacket, err := EncryptSessionKey(publicKey, sessionKey) if err != nil { return nil, "", errors.Wrap(err, "gopenpgp: unable to encrypt the session key") } // We join the key packets and datapackets ciphertext = crypto.NewPGPSplitMessage(keyPacket, messageDataPacket) encryptedSignature := crypto.NewPGPSplitMessage(keyPacket, signatureDataPacket) encryptedSignatureArmored, err = encryptedSignature.GetArmored() if err != nil { return nil, "", errors.Wrap(err, "gopenpgp: unable to armor encrypted signature") } return ciphertext, encryptedSignatureArmored, nil } func decryptVerifyObjDetached( publicKey, privateKey string, passphrase []byte, ciphertext *crypto.PGPMessage, encryptedSignatureArmored string, ) (message *crypto.PlainMessage, err error) { // We decrypt the message if message, err = decryptMessage(privateKey, passphrase, ciphertext); err != nil { return nil, err } encryptedSignature, err := crypto.NewPGPMessageFromArmored(encryptedSignatureArmored) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to parse encrypted signature") } // We decrypt the signature signatureMessage, err := decryptMessage(privateKey, passphrase, encryptedSignature) if err != nil { return nil, err } detachedSignature := crypto.NewPGPSignature(signatureMessage.GetBinary()) // We verify the signature var check bool if check, err = verifyDetached(publicKey, message, detachedSignature); err != nil { return nil, err } if !check { return nil, errors.New("gopenpgp: unable to verify message") } return message, nil } golang-github-protonmail-gopenpgp-2.8.1/helper/helper_test.go000066400000000000000000000225211472137343600244100ustar00rootroot00000000000000package helper import ( "bytes" "testing" "github.com/ProtonMail/gopenpgp/v2/crypto" "github.com/stretchr/testify/assert" ) func TestAESEncryption(t *testing.T) { var plaintext = "Symmetric secret" var passphrase = []byte("passphrase") ciphertext, err := EncryptMessageWithPassword(passphrase, plaintext) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } _, err = DecryptMessageWithPassword([]byte("Wrong passphrase"), ciphertext) assert.Containsf(t, err.Error(), "wrong password", "expected error containing 'wrong password', got %s", err) decrypted, err := DecryptMessageWithPassword(passphrase, ciphertext) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, plaintext, decrypted) } func TestArmoredTextMessageEncryption(t *testing.T) { var plaintext = "Secret message" armored, err := EncryptMessageArmored(readTestFile("keyring_publicKey", false), plaintext) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } assert.Exactly(t, true, crypto.IsPGPMessage(armored)) decrypted, err := DecryptMessageArmored( readTestFile("keyring_privateKey", false), testMailboxPassword, // Password defined in base_test armored, ) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, plaintext, decrypted) } func TestArmoredTextMessageEncryptionVerification(t *testing.T) { var plaintext = "Secret message" armored, err := EncryptSignMessageArmored( readTestFile("keyring_privateKey", false), readTestFile("keyring_privateKey", false), testMailboxPassword, // Password defined in base_test plaintext, ) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } assert.Exactly(t, true, crypto.IsPGPMessage(armored)) _, err = DecryptVerifyMessageArmored( readTestFile("mime_privateKey", false), // Wrong public key readTestFile("keyring_privateKey", false), testMailboxPassword, // Password defined in base_test armored, ) assert.EqualError(t, err, "gopenpgp: unable to decrypt message: Signature Verification Error: No matching signature") decrypted, err := DecryptVerifyMessageArmored( readTestFile("keyring_privateKey", false), readTestFile("keyring_privateKey", false), testMailboxPassword, // Password defined in base_test armored, ) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, plaintext, decrypted) } func TestAttachmentEncryptionVerification(t *testing.T) { var attachment = []byte("Secret file\r\nRoot password:hunter2") keyPacket, dataPacket, signature, err := EncryptSignAttachment( readTestFile("keyring_privateKey", false), readTestFile("keyring_privateKey", false), testMailboxPassword, // Password defined in base_test "password.txt", attachment, ) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } sig := crypto.NewPGPSignature(signature) armoredSig, err := sig.GetArmored() if err != nil { t.Fatal("Expected no error when armoring signature, got:", err) } _, err = DecryptVerifyAttachment( readTestFile("mime_privateKey", false), // Wrong public key readTestFile("keyring_privateKey", false), testMailboxPassword, // Password defined in base_test keyPacket, dataPacket, armoredSig, ) assert.EqualError(t, err, "gopenpgp: unable to verify attachment") decrypted, err := DecryptVerifyAttachment( readTestFile("keyring_privateKey", false), readTestFile("keyring_privateKey", false), testMailboxPassword, // Password defined in base_test keyPacket, dataPacket, armoredSig, ) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, attachment, decrypted) } func TestArmoredBinaryMessageEncryption(t *testing.T) { plainData := []byte("Secret message") armored, err := EncryptBinaryMessageArmored(readTestFile("keyring_privateKey", false), plainData) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } assert.Exactly(t, true, crypto.IsPGPMessage(armored)) decrypted, err := DecryptBinaryMessageArmored( readTestFile("keyring_privateKey", false), testMailboxPassword, // Password defined in base_test armored, ) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, plainData, decrypted) } func TestEncryptSignArmoredDetached(t *testing.T) { plainData := []byte("Secret message") privateKeyString := readTestFile("keyring_privateKey", false) privateKey, err := crypto.NewKeyFromArmored(privateKeyString) if err != nil { t.Fatal("Error reading the test private key: ", err) } publicKeyString, err := privateKey.GetArmoredPublicKey() if err != nil { t.Fatal("Error reading the test public key: ", err) } armoredCiphertext, armoredSignature, err := EncryptSignArmoredDetached( publicKeyString, privateKeyString, testMailboxPassword, // Password defined in base_test plainData, ) if err != nil { t.Fatal("Expected no error while encrypting and signing, got:", err) } decrypted, err := DecryptVerifyArmoredDetached( publicKeyString, privateKeyString, testMailboxPassword, armoredCiphertext, armoredSignature, ) if err != nil { t.Fatal("Expected no error while decrypting and verifying, got:", err) } if !bytes.Equal(decrypted, plainData) { t.Error("Decrypted is not equal to the plaintext") } _, modifiedSignature, err := EncryptSignArmoredDetached( publicKeyString, privateKeyString, testMailboxPassword, // Password defined in base_test []byte("Different message"), ) if err != nil { t.Fatal("Expected no error while encrypting and signing, got:", err) } _, err = DecryptVerifyArmoredDetached( publicKeyString, privateKeyString, testMailboxPassword, armoredCiphertext, modifiedSignature, ) if err == nil { t.Fatal("Expected an error while decrypting and verifying with a wrong signature") } } func TestEncryptDecryptAttachmenWithKey(t *testing.T) { plainData := []byte("Secret message") privateKeyString := readTestFile("keyring_privateKey", false) privateKey, err := crypto.NewKeyFromArmored(privateKeyString) if err != nil { t.Fatal("Error reading the test private key: ", err) } publicKeyString, err := privateKey.GetArmoredPublicKey() if err != nil { t.Fatal("Error reading the test public key: ", err) } pgpSplitMessage, err := EncryptAttachmentWithKey( publicKeyString, "test_filename", plainData, ) if err != nil { t.Fatal("Expected no error while encrypting, got:", err) } decrypted, err := DecryptAttachmentWithKey( privateKeyString, testMailboxPassword, pgpSplitMessage.KeyPacket, pgpSplitMessage.DataPacket, ) if err != nil { t.Fatal("Expected no error while decrypting, got:", err) } if !bytes.Equal(decrypted, plainData) { t.Error("Decrypted attachment is not equal to the original attachment") } } func TestEncryptDecryptSessionKey(t *testing.T) { privateKeyString := readTestFile("keyring_privateKey", false) privateKey, err := crypto.NewKeyFromArmored(privateKeyString) if err != nil { t.Fatal("Error reading the test private key: ", err) } publicKeyString, err := privateKey.GetArmoredPublicKey() if err != nil { t.Fatal("Error reading the test public key: ", err) } sessionKey, err := crypto.GenerateSessionKeyAlgo("aes256") if err != nil { t.Fatal("Expected no error while generating the session key, got:", err) } encrypted, err := EncryptSessionKey(publicKeyString, sessionKey) if err != nil { t.Fatal("Expected no error while encrypting session key, got:", err) } decryptedSessionKey, err := DecryptSessionKey( privateKeyString, testMailboxPassword, encrypted, ) if err != nil { t.Fatal("Expected no error while decrypting session key, got:", err) } if decryptedSessionKey.GetBase64Key() != sessionKey.GetBase64Key() { t.Error("Decrypted session key is not equal to the original session key") } } func TestEncryptSignBinaryDetached(t *testing.T) { plainData := []byte("Secret message") privateKeyString := readTestFile("keyring_privateKey", false) privateKey, err := crypto.NewKeyFromArmored(privateKeyString) if err != nil { t.Fatal("Error reading the test private key: ", err) } publicKeyString, err := privateKey.GetArmoredPublicKey() if err != nil { t.Fatal("Error reading the test public key: ", err) } encryptedData, armoredSignature, err := EncryptSignBinaryDetached( publicKeyString, privateKeyString, testMailboxPassword, // Password defined in base_test plainData, ) if err != nil { t.Fatal("Expected no error while encrypting and signing, got:", err) } decrypted, err := DecryptVerifyBinaryDetached( publicKeyString, privateKeyString, testMailboxPassword, encryptedData, armoredSignature, ) if err != nil { t.Fatal("Expected no error while decrypting and verifying, got:", err) } if !bytes.Equal(decrypted, plainData) { t.Error("Decrypted is not equal to the plaintext") } _, modifiedSignature, err := EncryptSignBinaryDetached( publicKeyString, privateKeyString, testMailboxPassword, // Password defined in base_test []byte("Different message"), ) if err != nil { t.Fatal("Expected no error while encrypting and signing, got:", err) } _, err = DecryptVerifyBinaryDetached( publicKeyString, privateKeyString, testMailboxPassword, encryptedData, modifiedSignature, ) if err == nil { t.Fatal("Expected an error while decrypting and verifying with a wrong signature") } } golang-github-protonmail-gopenpgp-2.8.1/helper/key.go000066400000000000000000000034611472137343600226640ustar00rootroot00000000000000package helper import ( "github.com/ProtonMail/gopenpgp/v2/crypto" "github.com/pkg/errors" ) // UpdatePrivateKeyPassphrase decrypts the given armored privateKey with oldPassphrase, // re-encrypts it with newPassphrase, and returns the new armored key. func UpdatePrivateKeyPassphrase( privateKey string, oldPassphrase, newPassphrase []byte, ) (string, error) { key, err := crypto.NewKeyFromArmored(privateKey) if err != nil { return "", errors.Wrap(err, "gopenpgp: unable to parse key") } unlocked, err := key.Unlock(oldPassphrase) if err != nil { return "", errors.Wrap(err, "gopenpgp: unable to unlock old key") } defer unlocked.ClearPrivateParams() locked, err := unlocked.Lock(newPassphrase) if err != nil { return "", errors.Wrap(err, "gopenpgp: unable to lock new key") } armored, err := locked.Armor() if err != nil { return "", errors.Wrap(err, "gopenpgp: unable to armor new key") } return armored, nil } // GenerateKey generates a key of the given keyType ("rsa" or "x25519"), encrypts it, and returns an armored string. // If keyType is "rsa", bits is the RSA bitsize of the key. // If keyType is "x25519" bits is unused. func GenerateKey(name, email string, passphrase []byte, keyType string, bits int) (string, error) { key, err := crypto.GenerateKey(name, email, keyType, bits) if err != nil { return "", errors.Wrap(err, "gopenpgp: unable to generate new key") } defer key.ClearPrivateParams() locked, err := key.Lock(passphrase) if err != nil { return "", errors.Wrap(err, "gopenpgp: unable to lock new key") } return locked.Armor() } func GetSHA256Fingerprints(publicKey string) ([]string, error) { key, err := crypto.NewKeyFromArmored(publicKey) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to parse key") } return key.GetSHA256Fingerprints(), nil } golang-github-protonmail-gopenpgp-2.8.1/helper/key_test.go000066400000000000000000000010321472137343600237130ustar00rootroot00000000000000package helper import ( "testing" "github.com/stretchr/testify/assert" ) func TestGetSHA256FingerprintsV4(t *testing.T) { sha256Fingerprints, err := GetSHA256Fingerprints(readTestFile("keyring_publicKey", false)) if err != nil { t.Fatal("Cannot unarmor key:", err) } assert.Len(t, sha256Fingerprints, 2) assert.Exactly(t, "d9ac0b857da6d2c8be985b251a9e3db31e7a1d2d832d1f07ebe838a9edce9c24", sha256Fingerprints[0]) assert.Exactly(t, "203dfba1f8442c17e59214d9cd11985bfc5cc8721bb4a71740dd5507e58a1a0d", sha256Fingerprints[1]) } golang-github-protonmail-gopenpgp-2.8.1/helper/message.go000066400000000000000000000020501472137343600235110ustar00rootroot00000000000000package helper import "github.com/ProtonMail/gopenpgp/v2/crypto" // EncryptPGPMessageToAdditionalKey decrypts the session key of the input PGPSplitMessage with a private key in keyRing // and encrypts it towards the additionalKeys by adding the additional key packets to the input PGPSplitMessage. // If successful, new key packets are added to message. // * messageToModify : The encrypted pgp message that should be modified // * keyRing : The private keys to decrypt the session key in the messageToModify. // * additionalKey : The public keys the message should be additionally encrypted to. func EncryptPGPMessageToAdditionalKey(messageToModify *crypto.PGPSplitMessage, keyRing *crypto.KeyRing, additionalKey *crypto.KeyRing) error { sessionKey, err := keyRing.DecryptSessionKey(messageToModify.KeyPacket) if err != nil { return err } additionalKeyPacket, err := additionalKey.EncryptSessionKey(sessionKey) if err != nil { return err } messageToModify.KeyPacket = append(messageToModify.KeyPacket, additionalKeyPacket...) return nil } golang-github-protonmail-gopenpgp-2.8.1/helper/message_test.go000066400000000000000000000030561472137343600245570ustar00rootroot00000000000000package helper_test import ( "testing" "github.com/ProtonMail/gopenpgp/v2/crypto" "github.com/ProtonMail/gopenpgp/v2/helper" "github.com/stretchr/testify/assert" ) func TestEncryptPGPMessageToAdditionalKey(t *testing.T) { keyA, err := crypto.GenerateKey("A", "a@a.a", "x25519", 0) if err != nil { t.Fatal("Expected no error when generating key, got:", err) } keyB, err := crypto.GenerateKey("B", "b@b.b", "x25519", 0) if err != nil { t.Fatal("Expected no error when generating key, got:", err) } keyRingA, err := crypto.NewKeyRing(keyA) if err != nil { t.Fatal("Expected no error when creating keyring, got:", err) } keyRingB, err := crypto.NewKeyRing(keyB) if err != nil { t.Fatal("Expected no error when creating keyring, got:", err) } message := crypto.NewPlainMessageFromString("plain text") // Encrypt towards A ciphertext, err := keyRingA.Encrypt(message, nil) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } ciphertextSplit, err := ciphertext.SplitMessage() if err != nil { t.Fatal("Expected no error when splitting message, got:", err) } // Also encrypt the message towards B if err := helper.EncryptPGPMessageToAdditionalKey(ciphertextSplit, keyRingA, keyRingB); err != nil { t.Fatal("Expected no error when modifying the message, got:", err) } // Test decrypt with B decrypted, err := keyRingB.Decrypt( ciphertextSplit.GetPGPMessage(), nil, 0, ) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, message.GetString(), decrypted.GetString()) } golang-github-protonmail-gopenpgp-2.8.1/helper/mobile.go000066400000000000000000000145361472137343600233500ustar00rootroot00000000000000package helper import ( "encoding/json" goerrors "errors" "runtime/debug" "github.com/ProtonMail/gopenpgp/v2/crypto" "github.com/pkg/errors" ) type ExplicitVerifyMessage struct { Message *crypto.PlainMessage SignatureVerificationError *crypto.SignatureVerificationError } // DecryptExplicitVerify decrypts a PGP message given a private keyring // and a public keyring to verify the embedded signature. Returns the plain // data and an error on signature verification failure. func DecryptExplicitVerify( pgpMessage *crypto.PGPMessage, privateKeyRing, publicKeyRing *crypto.KeyRing, verifyTime int64, ) (*ExplicitVerifyMessage, error) { message, err := privateKeyRing.Decrypt(pgpMessage, publicKeyRing, verifyTime) return newExplicitVerifyMessage(message, err) } // DecryptExplicitVerifyWithContext decrypts a PGP message given a private keyring // and a public keyring to verify the embedded signature. Returns the plain // data and an error on signature verification failure. // The caller can provide a context that will be used to verify the signature. func DecryptExplicitVerifyWithContext( pgpMessage *crypto.PGPMessage, privateKeyRing, publicKeyRing *crypto.KeyRing, verifyTime int64, verificationContext *crypto.VerificationContext, ) (*ExplicitVerifyMessage, error) { message, err := privateKeyRing.DecryptWithContext(pgpMessage, publicKeyRing, verifyTime, verificationContext) return newExplicitVerifyMessage(message, err) } // DecryptSessionKeyExplicitVerify decrypts a PGP data packet given a session key // and a public keyring to verify the embedded signature. Returns the plain data and // an error on signature verification failure. func DecryptSessionKeyExplicitVerify( dataPacket []byte, sessionKey *crypto.SessionKey, publicKeyRing *crypto.KeyRing, verifyTime int64, ) (*ExplicitVerifyMessage, error) { message, err := sessionKey.DecryptAndVerify(dataPacket, publicKeyRing, verifyTime) return newExplicitVerifyMessage(message, err) } // DecryptSessionKeyExplicitVerifyWithContext decrypts a PGP data packet given a session key // and a public keyring to verify the embedded signature. Returns the plain data and // an error on signature verification failure. // The caller can provide a context that will be used to verify the signature. func DecryptSessionKeyExplicitVerifyWithContext( dataPacket []byte, sessionKey *crypto.SessionKey, publicKeyRing *crypto.KeyRing, verifyTime int64, verificationContext *crypto.VerificationContext, ) (*ExplicitVerifyMessage, error) { message, err := sessionKey.DecryptAndVerifyWithContext(dataPacket, publicKeyRing, verifyTime, verificationContext) return newExplicitVerifyMessage(message, err) } func newExplicitVerifyMessage(message *crypto.PlainMessage, err error) (*ExplicitVerifyMessage, error) { var explicitVerify *ExplicitVerifyMessage if err != nil { castedErr := &crypto.SignatureVerificationError{} isType := goerrors.As(err, castedErr) if !isType { return nil, errors.Wrap(err, "gopenpgp: unable to decrypt message") } explicitVerify = &ExplicitVerifyMessage{ Message: message, SignatureVerificationError: castedErr, } } else { explicitVerify = &ExplicitVerifyMessage{ Message: message, SignatureVerificationError: nil, } } return explicitVerify, nil } // DecryptAttachment takes a keypacket and datpacket // and returns a decrypted PlainMessage // Specifically designed for attachments rather than text messages. func DecryptAttachment(keyPacket []byte, dataPacket []byte, keyRing *crypto.KeyRing) (*crypto.PlainMessage, error) { splitMessage := crypto.NewPGPSplitMessage(keyPacket, dataPacket) decrypted, err := keyRing.DecryptAttachment(splitMessage) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to decrypt attachment") } return decrypted, nil } // EncryptAttachment encrypts a file given a plainData and a fileName. // Returns a PGPSplitMessage containing a session key packet and symmetrically // encrypted data. Specifically designed for attachments rather than text // messages. func EncryptAttachment(plainData []byte, filename string, keyRing *crypto.KeyRing) (*crypto.PGPSplitMessage, error) { plainMessage := crypto.NewPlainMessageFromFile(plainData, filename, uint32(crypto.GetUnixTime())) decrypted, err := keyRing.EncryptAttachment(plainMessage, "") if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to encrypt attachment") } return decrypted, nil } // GetJsonSHA256Fingerprints returns the SHA256 fingeprints of key and subkeys, // encoded in JSON, since gomobile can not handle arrays. func GetJsonSHA256Fingerprints(publicKey string) ([]byte, error) { key, err := crypto.NewKeyFromArmored(publicKey) if err != nil { return nil, errors.Wrap(err, "gopenpgp: unable to parse key") } return json.Marshal(key.GetSHA256Fingerprints()) } type EncryptSignArmoredDetachedMobileResult struct { CiphertextArmored, EncryptedSignatureArmored string } // EncryptSignArmoredDetachedMobile wraps the encryptSignArmoredDetached method // to have only one return argument for mobile. func EncryptSignArmoredDetachedMobile( publicKey, privateKey string, passphrase, plainData []byte, ) (wrappedTuple *EncryptSignArmoredDetachedMobileResult, err error) { ciphertext, encryptedSignature, err := encryptSignArmoredDetached(publicKey, privateKey, passphrase, plainData) if err != nil { return nil, err } return &EncryptSignArmoredDetachedMobileResult{ CiphertextArmored: ciphertext, EncryptedSignatureArmored: encryptedSignature, }, nil } type EncryptSignBinaryDetachedMobileResult struct { EncryptedData []byte EncryptedSignatureArmored string } // EncryptSignBinaryDetachedMobile wraps the encryptSignBinaryDetached method // to have only one return argument for mobile. func EncryptSignBinaryDetachedMobile( publicKey, privateKey string, passphrase, plainData []byte, ) (wrappedTuple *EncryptSignBinaryDetachedMobileResult, err error) { ciphertext, encryptedSignature, err := encryptSignBinaryDetached(publicKey, privateKey, passphrase, plainData) if err != nil { return nil, err } return &EncryptSignBinaryDetachedMobileResult{ EncryptedData: ciphertext, EncryptedSignatureArmored: encryptedSignature, }, nil } // 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-2.8.1/helper/mobile_stream.go000066400000000000000000000145751472137343600247260ustar00rootroot00000000000000package helper import ( "crypto/sha256" "hash" "io" "github.com/ProtonMail/gopenpgp/v2/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 } // VerifySignatureExplicit calls the reader's VerifySignature() // and tries to cast the returned error to a SignatureVerificationError. func VerifySignatureExplicit( reader *crypto.PlainMessageReader, ) (signatureVerificationError *crypto.SignatureVerificationError, err error) { if reader == nil { return nil, errors.New("gopenppg: the reader can't be nil") } err = reader.VerifySignature() if err != nil { castedErr := &crypto.SignatureVerificationError{} isType := errors.As(err, castedErr) if !isType { return } signatureVerificationError = castedErr err = nil } return } golang-github-protonmail-gopenpgp-2.8.1/helper/mobile_stream_test.go000066400000000000000000000221711472137343600257540ustar00rootroot00000000000000package helper import ( "bytes" "crypto/sha256" "errors" "io" "io/ioutil" "testing" "github.com/ProtonMail/gopenpgp/v2/constants" "github.com/ProtonMail/gopenpgp/v2/crypto" ) 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.KeyRing, *crypto.KeyRing, error) { testKey, err := crypto.GenerateKey("test", "test@protonmail.com", "x25519", 256) if err != nil { return nil, nil, err } testPublicKey, err := testKey.ToPublic() if err != nil { return nil, nil, err } testPrivateKeyRing, err := crypto.NewKeyRing(testKey) if err != nil { return nil, nil, err } testPublicKeyRing, err := crypto.NewKeyRing(testPublicKey) if err != nil { return nil, nil, err } return testPublicKeyRing, testPrivateKeyRing, nil } func TestExplicitVerifyAllGoesWell(t *testing.T) { data := []byte("hello") pubKR, privKR, err := setUpTestKeyRing() if err != nil { t.Fatalf("Got an error while loading test key: %v", err) } defer privKR.ClearPrivateParams() ciphertext, err := pubKR.Encrypt(crypto.NewPlainMessage(data), privKR) if err != nil { t.Fatalf("Got an error while encrypting test data: %v", err) } reader, err := privKR.DecryptStream( bytes.NewReader(ciphertext.Data), pubKR, crypto.GetUnixTime(), ) if err != nil { t.Fatalf("Got an error while decrypting stream data: %v", err) } _, err = ioutil.ReadAll(reader) if err != nil { t.Fatalf("Got an error while reading decrypted data: %v", err) } sigErr, err := VerifySignatureExplicit(reader) if sigErr != nil { t.Fatalf("Got a signature error while verifying embedded sig: %v", sigErr) } if err != nil { t.Fatalf("Got an error while verifying embedded sig: %v", err) } } func TestExplicitVerifyTooEarly(t *testing.T) { data := []byte("hello") pubKR, privKR, err := setUpTestKeyRing() if err != nil { t.Fatalf("Got an error while loading test key: %v", err) } defer privKR.ClearPrivateParams() ciphertext, err := pubKR.Encrypt(crypto.NewPlainMessage(data), privKR) if err != nil { t.Fatalf("Got an error while encrypting test data: %v", err) } reader, err := privKR.DecryptStream( bytes.NewReader(ciphertext.Data), pubKR, crypto.GetUnixTime(), ) 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 := VerifySignatureExplicit(reader) if sigErr != nil { t.Fatalf("Got a signature error while verifying embedded sig: %v", sigErr) } if err == nil { t.Fatalf("Got no error while verifying a reader before reading it entirely") } } func TestExplicitVerifyNoSig(t *testing.T) { data := []byte("hello") pubKR, privKR, err := setUpTestKeyRing() if err != nil { t.Fatalf("Got an error while loading test key: %v", err) } defer privKR.ClearPrivateParams() ciphertext, err := pubKR.Encrypt(crypto.NewPlainMessage(data), nil) if err != nil { t.Fatalf("Got an error while encrypting test data: %v", err) } reader, err := privKR.DecryptStream( bytes.NewReader(ciphertext.Data), pubKR, crypto.GetUnixTime(), ) if err != nil { t.Fatalf("Got an error while decrypting stream data: %v", err) } _, err = ioutil.ReadAll(reader) if err != nil { t.Fatalf("Got an error while reading decrypted data: %v", err) } sigErr, err := VerifySignatureExplicit(reader) if sigErr == nil { t.Fatal("Got no signature error while verifying unsigned data") } if sigErr.Status != constants.SIGNATURE_NOT_SIGNED { t.Fatal("Signature error status was not SIGNATURE_NOT_SIGNED") } if err != nil { t.Fatalf("Got an error while verifying embedded sig: %v", err) } } func TestExplicitVerifyWrongVerifier(t *testing.T) { data := []byte("hello") 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() ciphertext, err := pubKR.Encrypt(crypto.NewPlainMessage(data), privKR2) if err != nil { t.Fatalf("Got an error while encrypting test data: %v", err) } reader, err := privKR.DecryptStream( bytes.NewReader(ciphertext.Data), pubKR, crypto.GetUnixTime(), ) if err != nil { t.Fatalf("Got an error while decrypting stream data: %v", err) } _, err = ioutil.ReadAll(reader) if err != nil { t.Fatalf("Got an error while reading decrypted data: %v", err) } sigErr, err := VerifySignatureExplicit(reader) if sigErr == nil { t.Fatal("Got no signature error while verifying with wrong key") } if sigErr.Status != constants.SIGNATURE_NO_VERIFIER { t.Fatal("Signature error status was not SIGNATURE_NO_VERIFIER") } if err != nil { t.Fatalf("Got an error while verifying embedded sig: %v", err) } } golang-github-protonmail-gopenpgp-2.8.1/helper/mobile_test.go000066400000000000000000000103071472137343600243770ustar00rootroot00000000000000package helper import ( "testing" "github.com/ProtonMail/gopenpgp/v2/constants" "github.com/ProtonMail/gopenpgp/v2/crypto" "github.com/stretchr/testify/assert" ) func TestMobileSignedMessageDecryption(t *testing.T) { privateKey, _ := crypto.NewKeyFromArmored(readTestFile("keyring_privateKey", false)) // Password defined in base_test privateKey, err := privateKey.Unlock(testMailboxPassword) if err != nil { t.Fatal("Expected no error unlocking privateKey, got:", err) } testPrivateKeyRing, _ := crypto.NewKeyRing(privateKey) publicKey, _ := crypto.NewKeyFromArmored(readTestFile("mime_publicKey", false)) testPublicKeyRing, _ := crypto.NewKeyRing(publicKey) pgpMessage, err := crypto.NewPGPMessageFromArmored(readTestFile("message_signed", false)) if err != nil { t.Fatal("Expected no error when unarmoring, got:", err) } decrypted, err := DecryptExplicitVerify(pgpMessage, testPrivateKeyRing, testPublicKeyRing, crypto.GetUnixTime()) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, constants.SIGNATURE_NO_VERIFIER, decrypted.SignatureVerificationError.Status) assert.Exactly(t, readTestFile("message_plaintext", true), decrypted.Message.GetString()) publicKey, _ = crypto.NewKeyFromArmored(readTestFile("keyring_publicKey", false)) testPublicKeyRing, _ = crypto.NewKeyRing(publicKey) pgpMessage, err = testPublicKeyRing.Encrypt(decrypted.Message, testPrivateKeyRing) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } decrypted, err = DecryptExplicitVerify(pgpMessage, testPrivateKeyRing, testPublicKeyRing, crypto.GetUnixTime()) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Nil(t, decrypted.SignatureVerificationError) assert.Exactly(t, readTestFile("message_plaintext", true), decrypted.Message.GetString()) decrypted, err = DecryptExplicitVerify(pgpMessage, testPublicKeyRing, testPublicKeyRing, crypto.GetUnixTime()) assert.NotNil(t, err) assert.Nil(t, decrypted) } func TestMobileSignedMessageDecryptionWithSessionKey(t *testing.T) { var message = crypto.NewPlainMessageFromString( "The secret code is... 1, 2, 3, 4, 5. I repeat: the secret code is... 1, 2, 3, 4, 5", ) privateKey, _ := crypto.NewKeyFromArmored(readTestFile("keyring_privateKey", false)) // Password defined in base_test privateKey, err := privateKey.Unlock(testMailboxPassword) if err != nil { t.Fatal("Expected no error unlocking privateKey, got:", err) } testPrivateKeyRing, _ := crypto.NewKeyRing(privateKey) publicKey, _ := crypto.NewKeyFromArmored(readTestFile("keyring_publicKey", false)) testPublicKeyRing, _ := crypto.NewKeyRing(publicKey) sk, err := crypto.GenerateSessionKey() if err != nil { t.Fatal("Expected no error generating session key, got:", err) } pgpMessage, err := sk.Encrypt(message) if err != nil { t.Fatal("Expected no error when unarmoring, got:", err) } decrypted, err := DecryptSessionKeyExplicitVerify(pgpMessage, sk, testPublicKeyRing, crypto.GetUnixTime()) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Exactly(t, constants.SIGNATURE_NOT_SIGNED, decrypted.SignatureVerificationError.Status) assert.Exactly(t, message.GetString(), decrypted.Message.GetString()) publicKey, _ = crypto.NewKeyFromArmored(readTestFile("keyring_publicKey", false)) testPublicKeyRing, _ = crypto.NewKeyRing(publicKey) pgpMessage, err = sk.EncryptAndSign(message, testPrivateKeyRing) if err != nil { t.Fatal("Expected no error when encrypting, got:", err) } decrypted, err = DecryptSessionKeyExplicitVerify(pgpMessage, sk, testPublicKeyRing, crypto.GetUnixTime()) if err != nil { t.Fatal("Expected no error when decrypting, got:", err) } assert.Nil(t, decrypted.SignatureVerificationError) assert.Exactly(t, message.GetString(), decrypted.Message.GetString()) } func TestGetJsonSHA256FingerprintsV4(t *testing.T) { sha256Fingerprints, err := GetJsonSHA256Fingerprints(readTestFile("keyring_publicKey", false)) if err != nil { t.Fatal("Cannot unarmor key:", err) } assert.Exactly(t, []byte("[\"d9ac0b857da6d2c8be985b251a9e3db31e7a1d2d832d1f07ebe838a9edce9c24\",\"203dfba1f8442c17e59214d9cd11985bfc5cc8721bb4a71740dd5507e58a1a0d\"]"), sha256Fingerprints) } golang-github-protonmail-gopenpgp-2.8.1/helper/sign_detached.go000066400000000000000000000054001472137343600246500ustar00rootroot00000000000000//go:build !ios && !android // +build !ios,!android package helper import ( "github.com/ProtonMail/gopenpgp/v2/crypto" "github.com/pkg/errors" ) // EncryptSignAttachment encrypts an attachment using a detached signature, given a publicKey, a privateKey // and its passphrase, the filename, and the unencrypted file data. // Returns keypacket, dataPacket and unarmored (!) signature separate. func EncryptSignAttachment( publicKey, privateKey string, passphrase []byte, filename string, plainData []byte, ) (keyPacket, dataPacket, signature []byte, err error) { var privateKeyObj, unlockedKeyObj *crypto.Key var publicKeyRing, privateKeyRing *crypto.KeyRing var packets *crypto.PGPSplitMessage var signatureObj *crypto.PGPSignature var binMessage = crypto.NewPlainMessageFromFile(plainData, filename, uint32(crypto.GetUnixTime())) if publicKeyRing, err = createPublicKeyRing(publicKey); err != nil { return nil, nil, nil, err } if privateKeyObj, err = crypto.NewKeyFromArmored(privateKey); err != nil { return nil, nil, nil, errors.Wrap(err, "gopenpgp: unable to parse private key") } if unlockedKeyObj, err = privateKeyObj.Unlock(passphrase); err != nil { return nil, nil, nil, errors.Wrap(err, "gopenpgp: unable to unlock key") } defer unlockedKeyObj.ClearPrivateParams() if privateKeyRing, err = crypto.NewKeyRing(unlockedKeyObj); err != nil { return nil, nil, nil, errors.Wrap(err, "gopenpgp: unable to create private keyring") } if packets, err = publicKeyRing.EncryptAttachment(binMessage, ""); err != nil { return nil, nil, nil, errors.Wrap(err, "gopenpgp: unable to encrypt attachment") } if signatureObj, err = privateKeyRing.SignDetached(binMessage); err != nil { return nil, nil, nil, errors.Wrap(err, "gopenpgp: unable to sign attachment") } return packets.GetBinaryKeyPacket(), packets.GetBinaryDataPacket(), signatureObj.GetBinary(), nil } // EncryptSignArmoredDetached takes a public key for encryption, // a private key and its passphrase for signature, and the plaintext data // Returns an armored ciphertext and a detached armored signature. func EncryptSignArmoredDetached( publicKey, privateKey string, passphrase, plainData []byte, ) (ciphertextArmored, encryptedSignatureArmored string, err error) { return encryptSignArmoredDetached(publicKey, privateKey, passphrase, plainData) } // EncryptSignBinaryDetached takes a public key for encryption, // a private key and its passphrase for signature, and the plaintext data // Returns encrypted binary data and a detached armored encrypted signature. func EncryptSignBinaryDetached( publicKey, privateKey string, passphrase, plainData []byte, ) (encryptedData []byte, encryptedSignatureArmored string, err error) { return encryptSignBinaryDetached(publicKey, privateKey, passphrase, plainData) } golang-github-protonmail-gopenpgp-2.8.1/internal/000077500000000000000000000000001472137343600220765ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-2.8.1/internal/armor.go000066400000000000000000000005551472137343600235520ustar00rootroot00000000000000package internal import ( "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 } golang-github-protonmail-gopenpgp-2.8.1/internal/common.go000066400000000000000000000014701472137343600237170ustar00rootroot00000000000000// Package internal contains internal methods and constants. package internal import ( "strings" "github.com/ProtonMail/gopenpgp/v2/constants" ) func Canonicalize(text string) string { return strings.ReplaceAll(strings.ReplaceAll(text, "\r\n", "\n"), "\n", "\r\n") } 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") } // CreationTimeOffset stores the amount of seconds that a signature may be // created in the future, to compensate for clock skew. const CreationTimeOffset = int64(60 * 60 * 24 * 2) // ArmorHeaders is a map of default armor headers. var ArmorHeaders = map[string]string{ "Version": constants.ArmorHeaderVersion, "Comment": constants.ArmorHeaderComment, } golang-github-protonmail-gopenpgp-2.8.1/models/000077500000000000000000000000001472137343600215455ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-2.8.1/models/models.go000066400000000000000000000003201472137343600233520ustar00rootroot00000000000000// Package models provides structs containing message data. package models // EncryptedSigned contains an encrypted message and signature. type EncryptedSigned struct { Encrypted string Signature string } golang-github-protonmail-gopenpgp-2.8.1/subtle/000077500000000000000000000000001472137343600215605ustar00rootroot00000000000000golang-github-protonmail-gopenpgp-2.8.1/subtle/subtle.go000066400000000000000000000021241472137343600234040ustar00rootroot00000000000000// Package subtle contains subtly insecure methods not recommended for casual // use. package subtle import ( "crypto/aes" "crypto/cipher" "golang.org/x/crypto/scrypt" ) // EncryptWithoutIntegrity encrypts data with AES-CTR. Note: this encryption // mode is not secure when stored/sent on an untrusted medium. func EncryptWithoutIntegrity(key, input, iv []byte) (output []byte, err error) { var block cipher.Block if block, err = aes.NewCipher(key); err != nil { return } output = make([]byte, len(input)) stream := cipher.NewCTR(block, iv) stream.XORKeyStream(output, input) return } // DecryptWithoutIntegrity decrypts data encrypted with AES-CTR. func DecryptWithoutIntegrity(key, input, iv []byte) ([]byte, error) { // AES-CTR decryption is identical to encryption. return EncryptWithoutIntegrity(key, input, iv) } // DeriveKey derives a key from a password using scrypt. n should be set to the // highest power of 2 you can derive within 100 milliseconds. func DeriveKey(password string, salt []byte, n int) ([]byte, error) { return scrypt.Key([]byte(password), salt, n, 8, 1, 32) } golang-github-protonmail-gopenpgp-2.8.1/subtle/subtle_test.go000066400000000000000000000022031472137343600244410ustar00rootroot00000000000000package subtle import ( "encoding/hex" "testing" "github.com/stretchr/testify/assert" ) func TestSubtle_EncryptWithoutIntegrity(t *testing.T) { key, _ := hex.DecodeString("9469cccfc8a8d005247f39fa3e5b35a97db456cecf18deac6d84364d0818d763") plaintext := []byte("some plaintext") iv, _ := hex.DecodeString("c828f258a76aad7bc828f258a76aad7b") ciphertext, _ := EncryptWithoutIntegrity(key, plaintext, iv) assert.Exactly(t, "14697192f7e112fc88d83380693f", hex.EncodeToString(ciphertext)) } func TestSubtle_DecryptWithoutIntegrity(t *testing.T) { key, _ := hex.DecodeString("9469cccfc8a8d005247f39fa3e5b35a97db456cecf18deac6d84364d0818d763") ciphertext, _ := hex.DecodeString("14697192f7e112fc88d83380693f") iv, _ := hex.DecodeString("c828f258a76aad7bc828f258a76aad7b") plaintext, _ := DecryptWithoutIntegrity(key, ciphertext, iv) assert.Exactly(t, "some plaintext", string(plaintext)) } func TestSubtle_DeriveKey(t *testing.T) { salt, _ := hex.DecodeString("c828f258a76aad7b") dk, _ := DeriveKey("some password", salt, 32768) assert.Exactly(t, "9469cccfc8a8d005247f39fa3e5b35a97db456cecf18deac6d84364d0818d763", hex.EncodeToString(dk)) }