Giter Site home page Giter Site logo

protonmail / go-crypto Goto Github PK

View Code? Open in Web Editor NEW
310.0 20.0 94.0 6.54 MB

Fork of go/x/crypto, providing an up-to-date OpenPGP implementation

Home Page: https://pkg.go.dev/github.com/ProtonMail/go-crypto

License: BSD 3-Clause "New" or "Revised" License

Go 100.00%

go-crypto's Introduction

go get github.com/ProtonMail/go-crypto

This module is backwards compatible with x/crypto/openpgp, so you can simply replace all imports of golang.org/x/crypto/openpgp with github.com/ProtonMail/go-crypto/openpgp.

A partial list of changes is here: #21 (comment).

For the more extended API for reading and writing OpenPGP messages use github.com/ProtonMail/go-crypto/openpgp/v2, but it is not fully backwards compatible with golang.org/x/crypto/openpgp.

go-crypto's People

Contributors

aclements avatar agl avatar alrs avatar aviau avatar bradfitz avatar cixtor avatar cmars avatar davecheney avatar dchest avatar dmitris avatar dsymonds avatar filosottile avatar hanwen avatar ianlancetaylor avatar jonathanpittman avatar kardianos avatar katiehockman avatar kevinburke avatar lubux avatar marinthiercelin avatar minux avatar mundaym avatar rolandshoemaker avatar rsc avatar sanjanarajan avatar tklauser avatar twiss avatar wussler avatar x1ddos avatar zhj4478 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go-crypto's Issues

Is this repository alive ?

Hello there.

This repository is used by "github.com/go-git/go-git/v5" and its dependency brought me here.
And here I see no tags and no releases.
Why is it so empty ?
Is this repository alive ?

Thank you.

Unable to recognise signature from same key which is recognised and verified by GnuPG

Trying to verify a detached signature using the library fails with the following error, but it is recognised by GnuPG as a valid signature from the same key, am i using the method wrongly here?

openpgp: signature made by unknown entity

Following is the code i used to test this:

package main

import (
        "bytes"
        "fmt"
        "log"

        "github.com/ProtonMail/go-crypto/openpgp"
)

func verifyDetachedWithPubkey(msg, sig, pubkey string) error {
        keyring, err := openpgp.ReadArmoredKeyRing(bytes.NewBufferString(pubkey))
        if err != nil {
                return fmt.Errorf("failed to parse public key: %w", err)
        }

        if _, err = openpgp.CheckArmoredDetachedSignature(keyring, bytes.NewBufferString(msg), bytes.NewBufferString(sig), nil); err != nil {
                return fmt.Errorf("failed to check signature: %w", err)
        }
        return nil
}

func main() {
        // content of msg.txt
        msg := `a780aed82eea3a023b67247598f57ecf16c3d6fd80375cc3e2f1b564d2b9bc71  crc_hyperv_4.12.0_amd64.crcbundle
cbc75023e63fb33ce4a571ba2047c813acc04f68d6e51879e6a3b238913f54bb  crc_libvirt_4.12.0_amd64.crcbundle
d19c80e53f5c593908a09eb9b3f43ebd908db60ca2e54a01d87a8b09c208557f  crc_vfkit_4.12.0_amd64.crcbundle
59ec291480daf9e0a92978473b573f06fbb38ff5e1839ee7029aa77d2abea93a  crc_vfkit_4.12.0_arm64.crcbundle`
        // content of sig.asc.txt
        sig := `-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQIVAwUAY+4xjBmeL5H9Qx1RAQjKNw//S21soD5oPMiP6c+KUq53x6MsrtrYrBEm
45hHCSWdcijb4BmBiVXxrFq79ja4Q2RYJBTH0CdAiBF97GFfs4SUfAF4G8q2LJOB
qL1YwerR8ourBWo4fumJI3BmfAdNpm8io+W6alG5HYu8G6vyybOAWbLh0gKHKk0K
OOgyhxaTerGZ7XFzPOZL4efnMyKM0Ib82HKn2/Roi+bZj4pUJajhGrc8+Erxkiqd
rfUXyvsz+uCTU4BjBSAd1Da5RxXhcnvxX7Au/X73QSlWz66XGhlEiNHhgV0Vo/mh
mwdus2a2C+621F/dXnzLZBVCzMnb4kpWfaSHVl98sJUwGbs9Ca/5KbXjclC33Oj9
jncDaNzupgsc1voKWNjSsTYciXU6hwHn7UH/r4ZVcVoMQFAZ556myh83DNQiVL5U
njXacraP/QuL3UKTiJZFIHCKFCcM0Vib7kjESSmRzjf7ulZRHQbjGaOT97MNLNbA
3PlYG3FVswsKKCMeEQ447rHzBCTAzYClSaSh3YcBUFj1AqaLPAu2Bi3IbRmxaphs
NqUllRTN5lot/ER5eqcqWXhe+hfh8cCwo9ZSr2cnspQnSQWP+tB1FyxWeA0NvB/V
xMYXeJ6mUAR4wY3Ewf/OFPDbJzMpWIXmhe+Uj3uyVogAEd090XnJciZvTrxBdQrh
86iMeTHruu8=
=WfZk
-----END PGP SIGNATURE-----`
    // content of pubkey.txt
        pubkey := `-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.5 (GNU/Linux)

mQINBErgSTsBEACh2A4b0O9t+vzC9VrVtL1AKvUWi9OPCjkvR7Xd8DtJxeeMZ5eF
0HtzIG58qDRybwUe89FZprB1ffuUKzdE+HcL3FbNWSSOXVjZIersdXyH3NvnLLLF
0DNRB2ix3bXG9Rh/RXpFsNxDp2CEMdUvbYCzE79K1EnUTVh1L0Of023FtPSZXX0c
u7Pb5DI5lX5YeoXO6RoodrIGYJsVBQWnrWw4xNTconUfNPk0EGZtEnzvH2zyPoJh
XGF+Ncu9XwbalnYde10OCvSWAZ5zTCpoLMTvQjWpbCdWXJzCm6G+/hx9upke546H
5IjtYm4dTIVTnc3wvDiODgBKRzOl9rEOCIgOuGtDxRxcQkjrC+xvg5Vkqn7vBUyW
9pHedOU+PoF3DGOM+dqv+eNKBvh9YF9ugFAQBkcG7viZgvGEMGGUpzNgN7XnS1gj
/DPo9mZESOYnKceve2tIC87p2hqjrxOHuI7fkZYeNIcAoa83rBltFXaBDYhWAKS1
PcXS1/7JzP0ky7d0L6Xbu/If5kqWQpKwUInXtySRkuraVfuK3Bpa+X1XecWi24JY
HVtlNX025xx1ewVzGNCTlWn1skQN2OOoQTV4C8/qFpTW6DTWYurd4+fE0OJFJZQF
buhfXYwmRlVOgN5i77NTIJZJQfYFj38c/Iv5vZBPokO6mffrOTv3MHWVgQARAQAB
tDNSZWQgSGF0LCBJbmMuIChyZWxlYXNlIGtleSAyKSA8c2VjdXJpdHlAcmVkaGF0
LmNvbT6JAjYEEwECACAFAkrgSTsCGwMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAK
CRAZni+R/UMdUWzpD/9s5SFR/ZF3yjY5VLUFLMXIKUztNN3oc45fyLdTI3+UClKC
2tEruzYjqNHhqAEXa2sN1fMrsuKec61Ll2NfvJjkLKDvgVIh7kM7aslNYVOP6BTf
C/JJ7/ufz3UZmyViH/WDl+AYdgk3JqCIO5w5ryrC9IyBzYv2m0HqYbWfphY3uHw5
un3ndLJcu8+BGP5F+ONQEGl+DRH58Il9Jp3HwbRa7dvkPgEhfFR+1hI+Btta2C7E
0/2NKzCxZw7Lx3PBRcU92YKyaEihfy/aQKZCAuyfKiMvsmzs+4poIX7I9NQCJpyE
IGfINoZ7VxqHwRn/d5mw2MZTJjbzSf+Um9YJyA0iEEyD6qjriWQRbuxpQXmlAJbh
8okZ4gbVFv1F8MzK+4R8VvWJ0XxgtikSo72fHjwha7MAjqFnOq6eo6fEC/75g3NL
Ght5VdpGuHk0vbdENHMC8wS99e5qXGNDued3hlTavDMlEAHl34q2H9nakTGRF5Ki
JUfNh3DVRGhg8cMIti21njiRh7gyFI2OccATY7bBSr79JhuNwelHuxLrCFpY7V25
OFktl15jZJaMxuQBqYdBgSay2G0U6D1+7VsWufpzd/Abx1/c3oi9ZaJvW22kAggq
dzdA27UUYjWvx42w9menJwh/0jeQcTecIUd0d0rFcw/c1pvgMMl/Q73yzKgKYw==
=zbHE
-----END PGP PUBLIC KEY BLOCK-----`

        if err := verifyDetachedWithPubkey(msg, sig, pubkey); err != nil {
                log.Fatal(err)
        }
}

o/p of running the above code:

❯ go run main.go
2023/02/17 15:17:44 failed to check signature: openpgp: signature made by unknown entity
exit status 1

Following is o/p from gpg which is successfully able to verify the detached signature

❯ gpg --import pubkey.txt
gpg: key 199E2F91FD431D51: public key "Red Hat, Inc. (release key 2) <[email protected]>" imported
gpg: Total number processed: 1
gpg:               imported: 1

❯ gpg --list-keys
/tmp/tmp-gpg-home-dir/pubring.kbx
---------------------------------
pub   rsa4096 2009-10-22 [SC]
      567E347AD0044ADE55BA8A5F199E2F91FD431D51
uid           [ unknown] Red Hat, Inc. (release key 2) <[email protected]>

❯ gpg --verify msg.asc msg.txt
gpg: Signature made Thu Feb 16 19:07:16 2023 IST
gpg:                using RSA key 199E2F91FD431D51
gpg: Good signature from "Red Hat, Inc. (release key 2) <[email protected]>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 567E 347A D004 4ADE 55BA  8A5F 199E 2F91 FD43 1D51

sig.asc.txt
msg.txt
pubkey.txt

Loading encryption subkey to smartcard mutates fingerprint

Hello, I am trying to generate a ed+cv25519 signing+encryption key on a smartcard. When I push the keys to the smartcard using gpg-connect-agent, the encryption subkey fingerprint gets mutated relative to the one in my keyring.

Here is my debugging code to create an entity and output a secret key file

ent := []byte{
	0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
	0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
	0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
	0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
	0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
	0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
	0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
	0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40,
}
now := time.Unix(1709329403, 0)
cfgTime := func() time.Time { return now }
cfg := &propacket.Config{
	Rand:            bytes.NewReader(ent),
	Algorithm:       propacket.PubKeyAlgoEdDSA,
	Curve:           propacket.Curve25519,
	KeyLifetimeSecs: 0, // no expiration
	Time:            cfgTime,
	V5Keys:          false,
}
entity, err := propgp.NewEntity(keyID, "", "", cfg)

...

serNew := bytes.NewBuffer(nil)
err := entity.SerializePrivate(serNew, nil)
if err != nil {
	panic("SerializePrivate new" + err.Error())
}
_ = os.WriteFile(secretPath, serNew.Bytes(), 0644)

I load that key into my keyring and get the fingerprints + keygrips

>gpg --import <secretPath>
gpg: key EA0063F6C7ACB985: public key "test-sc" imported
gpg: key EA0063F6C7ACB985: secret key imported
gpg: Total number processed: 1
gpg:               imported: 1
gpg:       secret keys read: 1
gpg:  secret keys unchanged: 1

>gpg --show-key --with-colons <secretPath>                                                                                                  
sec:-:255:22:EA0063F6C7ACB985:1709329403:::-:::scESC:::::ed25519:::0:
fpr:::::::::D3A4BD8DD05557DC6C469D37EA0063F6C7ACB985:
grp:::::::::11FA927B453C99646DCE42A4EC33E7CDE9B5D80A:
uid:-::::1709329403::26898656831648DBFB10988947B1523808F13B24::test-sc::::::::::0:
ssb:-:255:18:9090FA627420EF33:1709329403::::::e:::::cv25519::
fpr:::::::::3CDC4501333D5FA52B98F28A9090FA627420EF33:
grp:::::::::6BD4B392CE9CA0994038B4ACB2A8EEA33C42B73B:

> gpg --with-subkey-fingerprints --list-key test-sc
pub   ed25519 2024-03-01 [SC]
      D3A4BD8DD05557DC6C469D37EA0063F6C7ACB985
uid           [ unknown] test-sc
sub   cv25519 2024-03-01 [E]
      3CDC4501333D5FA52B98F28A9090FA627420EF33

The fingerprints from the file match the ones in my keyring, as expected.

I then load the keys to the card:

NOTE: I am formatting the key's timestamp by converting it to a time.Time object and formatting with keyTimestamp.UTC().Format("20060102T150405")

>gpg-connect-agent 
> KEYTOCARD 11FA927B453C99646DCE42A4EC33E7CDE9B5D80A D2760001240100000006199714170000 OPENPGP.1 20240301T214323
> KEYTOCARD 6BD4B392CE9CA0994038B4ACB2A8EEA33C42B73B D2760001240100000006199714170000 OPENPGP.2 20240301T214323 
> /bye

However, when I run gpg --card-status, I see the following fingerprints:

Signature key ....: D3A4 BD8D D055 57DC 6C46  9D37 EA00 63F6 C7AC B985
      created ....: 2024-03-01 21:43:23
Encryption key....: 7684 69AC 284E EABB 2000  4B7C CFF6 8A7F 6CBA 9554
      created ....: 2024-03-01 21:43:23

The signature key's fingerprint matches the one in my keyring, but the encryption subkey does not.

If I instead generate a key with gpg, both fingerprints stay the same when loading to a smartcard:

>gpg --batch --passphrase "" --quick-generate-key test-sc-2 ed25519 sign never                                                                      
gpg: revocation certificate stored as '~/.gnupg/openpgp-revocs.d/0A842270AB61EFC33F2E298B1717B3D9583B854F.rev'

>gpg --batch --passphrase "" --quick-add-key 0A842270AB61EFC33F2E298B1717B3D9583B854F cv25519 encr never

> gpg --export-secret-key 0A842270AB61EFC33F2E298B1717B3D9583B854F > foo

> gpg --show-key --with-colons foo
sec:u:255:22:1717B3D9583B854F:1709585144:::u:::scESC:::::ed25519:::0:
fpr:::::::::0A842270AB61EFC33F2E298B1717B3D9583B854F:
grp:::::::::6D886491D5771C42D8ADF0BE748E79B86F7D8B4E:
uid:u::::1709585144::6B8541341C8D57622DF9AD9AE28036BCD5DB5D97::test-sc-2::::::::::0:
ssb:u:255:18:C5721B49EBE22FE3:1709585186::::::e:::::cv25519::
fpr:::::::::3F718B3457D3AC317031DCA2C5721B49EBE22FE3:
grp:::::::::7038DDE1064A68FB96BAF95D0EC985E309290599:

> gpg-connect-agent 
> KEYTOCARD 6D886491D5771C42D8ADF0BE748E79B86F7D8B4E D2760001240100000006199714170000 OPENPGP.1 20240304T204544
> KEYTOCARD 7038DDE1064A68FB96BAF95D0EC985E309290599 D2760001240100000006199714170000 OPENPGP.2 20240304T204626
> /bye

> gpg --card-status

...
Signature key ....: 0A84 2270 AB61 EFC3 3F2E  298B 1717 B3D9 583B 854F
      created ....: 2024-03-04 20:45:44
Encryption key....: 3F71 8B34 57D3 AC31 7031  DCA2 C572 1B49 EBE2 2FE3
      created ....: 2024-03-04 20:46:26
...

This behavior indicates some discrepancy being created in the go-crypto serialized secret file, like perhaps a field is not getting set, and then gets set by gpg-connect-agent when loading. However, I've tried a lot of different flags and the depth of Entity configuration is a bit dizzying so I thought I'd see if any of the maintainers have thoughts here.

A few notes:

  • Importantly, the encryption key cryptographically works just fine; if encryption/decryption functionality targets the card's primary key (i.e. ed25519) fingerprint, the encryption subkey is used, as you would expect. However, it's unsettling to see a discrepancy like this.
  • I am using go-crypto specifically to feed curated entropy into the rand reader, as I can find no way to do this with gpg. I need my gpg keys to be determinsitic
  • It is not possible to export a key/keyfile from a smartcard due to limitations in OpenPGP data persistence, so I can't see exactly what changed. And as mentioned above, I cannot find a way to feed specific entropy bytes to pgp when generating keys, so I can't cross compare that way either.
  • This issue presents itself for multiple smartcard types and manufacturers (Yubikey 5A + C, Nitrokey 3A + C)

Any help would be appreciated! Hopefully I've just overlooked something obvious in the configuration.

(Optionally?) skip HashTag quick test on verification

As discussed at https://mailarchive.ietf.org/arch/msg/openpgp/Zv8v1IwbbXYiDPKytfbUmtNdxak/ and hockeypuck/hockeypuck#187 (comment) , it appears that go-crypto is in the minority of implementations that fast-fails on the HashTag test at

if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] {
:

	hashBytes := signed.Sum(nil)
	if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] {
		return errors.SignatureError("hash tag doesn't match")
	}

Several known keys in the wild fail on this test yet successfully validate in other implementations, including GnuPG and Sequoia.

While go-crypto is technically correct here, the fast-fail test is not required by the standard and is sufficiently broken elsewhere that its usefulness is questionable.

How to use NewPublicKey

How should I use this function:
func NewPublicKey(curve ecc.EdDSACurve) *PublicKey
If ecc package is internal? I want to create keypair from scratch.

TestEndToEnd/ed25519_keygen fails randomly

TestEndToEnd/ed25519_keygen/encryptDecrypt/ed25519_keygen fails randomly

While pushing branch 26, the test TestEndToEnd/ed25519_keygen failed. See the log here. Branch 26 code does not use or modify the packages involved in the fail.

Reproduce the issue

Open openpgp/end_to_end_test.go and set

var testSets = []algorithmSet{}

and

var keySets = []keySet{
	{
		"ed25519",
		&packet.Config{Algorithm: packet.PubKeyAlgoEdDSA},
	},
}

(or just comment out the other values). With this,testSets will be populated with the randomly generated keys only, instead of checking the hardcoded set of constant test cases, speeding up tests.

Now run TestEndToEnd (go test -run TestEndToEnd -v) repeatedly until it fails (normally after some hundreds of iterations).
You can use this bash script in order to repeat until it fails

#!/bin/bash

i=1
while go test -run EndToEndTest -v; do
    echo "$i"
    ((i++))
done

crypto/ed25519.Verify is returning false

Meaning that the input public key, message, or signature are incorrect for this particular instance: sig[:32] is (very) different from checkR[:] at the end of this function.

This is one of the (failing) inputs actually delivered to Verify (printed from packet/public_key.go, function VerifySignature):

pk:      CC36F3A69DD47589849BFC18D48E3514B85A748420DF47C617895FC9E41D8D6F
message: 8C0B46F41CD35FED7ACDA4DF012014DDD25B33373A465C12057171A5B7EC2586
R:       5285A8D20B8AE70C1B65062C382C14081C344D937AEBB78FFFBA59414C6CD05C
S:       A1CB2811DF18E56D58B837A5E7A0B3C87F064475392E7116B25CC0250F60EA07
-(H(R,A,M) mod l)A + S*B: 
         7DF2FB6D05A554660FB0D8D736FB5E7AA9126105AA31DE5F1DEB6C5BE8898CA5

and this one passes (on the same run).

pk:       CC36F3A69DD47589849BFC18D48E3514B85A748420DF47C617895FC9E41D8D6F
message: 16D4AFDF311C863FA0EDA8EEF304FF3E6FD00D3311583BAEA125AA78921097FF
R:       370D516BE333FEB97E2AA7CCDF50AC50DE73D48BBF76A4ABE2B496784D6CD88E
S:       091A13521849BA8216C65069CC4D7CF129FCA1678DBEE9ACCE82A4B66F537B0F
-(H(R,A,M) mod l)A + S*B: 
         370D516BE333FEB97E2AA7CCDF50AC50DE73D48BBF76A4ABE2B496784D6CD88E

The verification equation on crypto/ed25519.go is to check whether R equals SB-(H(R,A,M) mod l)A. This assumes, that S < l and that the 2^c=8 factor is not important.

crypto/ed25519 Does not seem to be the source of the fail

Witnessed 10000 all-successful iterations of ed25519_test.go (with public, private, _ := GenerateKey(nil) instead of a zeroReader, in order to test random cases).

Consider removing unmodified packages and exporting only openpgp

Hello! We recently finally deprecated x/crypto/openpgp (golang/go#44226), and once the deprecation notice goes out I expect a number of users will move to forks like yours, which is great!

To make that migration happen smoothly and safely, I was hoping you'd consider removing or unexporting the non-openpgp packages. Assuming my understanding is correct, github.com/ProtonMail/go-crypto/openpgp is the only package that's meant to work differently in this fork, and the rest just reflect upstream.

If users put a replace statement in their go.mod for the whole x/crypto, they become blocked on your merges and releases to receive security fixes for any x/crypto package, like x/crypto/ssh or x/crypto/chacha20poly1305, which is unnecessary, a security risk, and toiling for your project.

Instead, users should be encouraged to require github.com/ProtonMail/go-crypto and use github.com/ProtonMail/go-crypto/openpgp, just like any third-party module.

Thank you!

Feature request for iOS local storage encryption

In order to replace CryptoSwift library in iOS project so far I'll need following methods:

  1. encryptSymmetrically(data: Data, with key: Data) -> Data
  2. decryptSymmetrically(data: Data, with key: Data) -> Data
  3. deriveStrongPassphrase(from pin: String, salt: Data, iterations: Int) -> Data

First two are used in accessors of AuthCredential, UserInfo and mailboxPassord, etc so they'll be called frequently and have to be as fast as possible. For symmetrical encryption I've been using AES with ECB block mode, with 32 byte keys.
The third one is used every time user unlocks the app with PIN, and i've found out that PBKDF2 of CryptoSwift with sha256 was disturbingly slow with more than 2000 iterations on iPhone 5S so I'd prefer to have opportunity to vary this number for different devices.

But actually cryptography is none of my fields of expertise so please feel free to change implementation details as you think would be better

Tests fail on 32bit architectures.

Dear go-crypto devs,

I realized that building a current go-crypto (3fbb1f1) for debian fails checks on armel, armhf and i386.
I checked out the current master on my amd64 laptop running debian stable and could reproduce it:

~/build/go-crypto/openpgp/s2k (git)-[main] % GOARCH=386 go test
--- FAIL: TestParseIntoParams (0.12s)
panic: runtime error: makeslice: len out of range [recovered]
	panic: runtime error: makeslice: len out of range

goroutine 301 [running]:
testing.tRunner.func1.2({0x8162f60, 0x81a547c})
	/usr/lib/go-1.19/src/testing/testing.go:1396 +0x2ab
testing.tRunner.func1()
	/usr/lib/go-1.19/src/testing/testing.go:1399 +0x41f
panic({0x8162f60, 0x81a547c})
	/usr/lib/go-1.19/src/runtime/panic.go:884 +0x1c3
golang.org/x/crypto/argon2.initBlocks(0x9116000, 0x400000, 0x4)
	/home/martin/build/go/pkg/mod/golang.org/x/[email protected]/argon2/argon2.go:158 +0x49
golang.org/x/crypto/argon2.deriveKey(0x2, {0x9018290, 0x5, 0x8}, {0x909c13a, 0x10, 0x10}, {0x0, 0x0, 0x0}, ...)
	/home/martin/build/go/pkg/mod/golang.org/x/[email protected]/argon2/argon2.go:113 +0x183
golang.org/x/crypto/argon2.IDKey(...)
	/home/martin/build/go/pkg/mod/golang.org/x/[email protected]/argon2/argon2.go:97
github.com/ProtonMail/go-crypto/openpgp/s2k.Argon2({0x9018288, 0x4, 0x4}, {0x9018290, 0x5, 0x8}, {0x909c13a, 0x10, 0x10}, 0x3, ...)
	/home/martin/build/go-crypto/openpgp/s2k/s2k.go:178 +0xb9
github.com/ProtonMail/go-crypto/openpgp/s2k.(*Params).Function.func4({0x9018288, 0x4, 0x4}, {0x9018290, 0x5, 0x8})
	/home/martin/build/go-crypto/openpgp/s2k/s2k.go:352 +0xae
github.com/ProtonMail/go-crypto/openpgp/s2k.TestParseIntoParams(0xd201c20)
	/home/martin/build/go-crypto/openpgp/s2k/s2k_test.go:172 +0x50d
testing.tRunner(0xd201c20, 0x8182ae4)
	/usr/lib/go-1.19/src/testing/testing.go:1446 +0x113
created by testing.(*T).Run
	/usr/lib/go-1.19/src/testing/testing.go:1493 +0x374
exit status 2
FAIL	github.com/ProtonMail/go-crypto/openpgp/s2k	2.156s

Support for OpenPGP V3 signatures

I work on a project that verifies signed RPM packages, which still use OpenPGP V3 signatures. Both the Golang RPM library and our service's verifier have to use x/crypto/openpgp, but we'd like to migrate to using this library to pick up support for other key types, bug fixes, etc. Is there any interest in bringing back support for V3 signatures? We don't need generation of them, only verification.

Test compatibility with GnuPG

Compatibility with gpg

GnuPG is a well-known [...] complete and free implementation of the OpenPGP standard defined in RFC4880. As such, consistency betweengpg and golang/crypto/openpgp (and also OpenPGPjs) should be tested, in order to detect deviations from the specification or bugs.

Precedent issues

See #39 (how gpg assumes ECDH keys come already masked), and #38 (example of file encryption tests between both libraries).

Cross-library testing

Use the new integrationtests package at the openpgp level, introduced in #37, in order to randomize and automate the testing (as done in #39 test files by @izouxv).

These should include

  • import/export keys from/to gpg,
  • encrypt/decrypt messages, files,
  • signing and signature verification,

and may test both the correct and malicious/incorrect scenarios.

Failing Tests (Panic) on ppc64el

Hi,

Thanks for your work on this package. However, while running tests on ppc64el, the brainpool/brainpool_test.go gives out panic error messages:

$ go test -v ./brainpool 
=== RUN   TestP256r1
--- FAIL: TestP256r1 (0.00s)
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
	panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x30 pc=0x11695c]

goroutine 6 [running]:
testing.tRunner.func1.2({0x142a40, 0x246950})
	/usr/lib/go-1.17/src/testing/testing.go:1209 +0x27c
testing.tRunner.func1(0xc00012e000)
	/usr/lib/go-1.17/src/testing/testing.go:1212 +0x228
panic({0x142a40, 0x246950})
	/usr/lib/go-1.17/src/runtime/panic.go:1038 +0x240
crypto/elliptic.matchesSpecificCurve(0xc00007e6c0, {0xc000104d80, 0x3, 0x3})
	/usr/lib/go-1.17/src/crypto/elliptic/elliptic.go:45 +0x7c
crypto/elliptic.(*CurveParams).ScalarBaseMult(0xc00007e6c0, {0xc00001a080, 0x20, 0x20})
	/usr/lib/go-1.17/src/crypto/elliptic/elliptic.go:313 +0xbc
github.com/ProtonMail/go-crypto/brainpool.(*rcurve).ScalarBaseMult(0xc0000101e0, {0xc00001a080, 0x20, 0x20})
	/home/nilesh/proto/go-crypto/brainpool/rcurve.go:82 +0x54
crypto/ecdsa.GenerateKey({0x190208, 0xc0000101e0}, {0x18d3c0, 0xc00007a1e0})
	/usr/lib/go-1.17/src/crypto/ecdsa/ecdsa.go:158 +0x168
github.com/ProtonMail/go-crypto/brainpool.testCurve(0xc00012e000, {0x190208, 0xc0000101e0})
	/home/nilesh/proto/go-crypto/brainpool/brainpool_test.go:11 +0x50
github.com/ProtonMail/go-crypto/brainpool.TestP256r1(0xc00012e000)
	/home/nilesh/proto/go-crypto/brainpool/brainpool_test.go:32 +0x80
testing.tRunner(0xc00012e000, 0x168828)
	/usr/lib/go-1.17/src/testing/testing.go:1259 +0xe8
created by testing.(*T).Run
	/usr/lib/go-1.17/src/testing/testing.go:1306 +0x370
FAIL	github.com/ProtonMail/go-crypto/brainpool	0.006s
FAIL

Could you check what might be wrong?

===================================================================================================

CC: @twiss

Missing FlagAuthenticate in packet.Signature

I expected to find FlagAuthenticate in https://github.com/ProtonMail/go-crypto/blob/a4f6767435ab/openpgp/packet/signature.go#L34 since that's part of the spec as 0x20: https://www.rfc-editor.org/rfc/rfc4880.html#section-5.2.3.21

There's a patch created by @chaosaffe that fixes this, and it applies to your code base without issues. It can be found at https://go-review.googlesource.com/c/crypto/+/120315 and it was discussed in golang/go#25983.

Any chance you could add this? (I was about to create a pull request, but seeing your Contribution Policy, I didn't.)

Go-crypto encrypts with the expired subkey

Given a public key with 2 subkeys where the first one is expired and the second one is valid, go-crypto will encrypt with expired subkey instead of the valid second subkey.

I tried this with the following key:

-----BEGIN PGP PUBLIC KEY BLOCK-----

mI0EW5kE2gEEAN3QcfWzMQCniICMlLJg3LgHtobUyQbv+PO1wPbBTdTo5XddwMVO
ef2QN+MNy4UXmRtjUoaWEvHzYQ1a8t10fUI0IyIjc2LhQDm2Wye6xXLrTxV0rWyp
HjC5027fQjaNiyuBUCU9cG78mwZVFTw0lboWryHjqZuBoF2mPHopTaaxABEBAAG0
JWV4cGlyYXRpb24gdGVzdCA8ZXhwaXJhdGlvbkB0ZXN0LmNvbT6IzgQTAQgAOBYh
BPjBOFw5rULVXFVgVMkCMBoLuY3LBQJbmQTaAhsDBQsJCAcCBhUKCQgLAgQWAgMB
Ah4BAheAAAoJEMkCMBoLuY3LwCQD/jCUZkJj8dTNmcn/3lGceL7IxGrh7oFEks9s
bwWsMhi5i6KUxCoYnmm9kp/E1mLDE9JufXzJB+bvaCyCRPjS1hksoCTdcIVOuggc
mtO5I+0ArW32mFHgLK1Dz6JrV8T4jiVkwpuD6YcTlL3O4ebGdCRyK4ICvHmSbRT5
DX9A4XbpuI0EW5kE2gEEAJmcO5EPemO/04X1XFwktOhSFUg7iwGHjNmqv15PhloP
NtjraL0K7rzYrC/cvaOBHQg8Va2MB11HkxUx50C1kBQf8K3BEhcFQwLpDjyocniu
gFqUigNlQLP+xFkaYZfhxajPGzhUe+ja6GjcthYYV0F1QtooaQEy0C0cs7e5Cfot
ABEBAAGIvAQYAQgAJgIbDBYhBPjBOFw5rULVXFVgVMkCMBoLuY3LBQJbmQhHBQkA
AVTtAAoJEMkCMBoLuY3LWr8EANCDuRF0i9SSEo+eDeqsMGPcy56J1rJz6YBrr+sE
hjz72pMy/LgTEucsc2Ag4SBO2ULxDj8A1o8M0wovqol57UgzkyzjqmsndyHgGP5+
Zbrv9MFSY3S4PFCdvQRF4svp/nZ7TFmeX2BLYZH2KIE7m4wKIWsDy30mm33A+VbI
EE1DuI0EW5kIbgEEAM38fxqrvdThdAwH9lSVR6Tb7JE4ASFY0j2EpDft1byBOiDm
sSkdZfaMal4ItHbbqsNeKxDW6DFda0VS5zeamPl2/GD8X/lzyBYrV6iqqRKu4zql
q3JSWRjkhcuJy48IwUQ0OR8cUrqK174cWylXY5mvjqJqxeI+dVxnvLC0lEdtABEB
AAGIvAQYAQgAJhYhBPjBOFw5rULVXFVgVMkCMBoLuY3LBQJbmQhuAhsMBQkJZgGA
AAoJEMkCMBoLuY3L6p8D/jwJkrNLrsBCDEv+7uIQWaXu9dn5sUY1hR2V8eIQo7yp
r7Wg1nvgd7aRzevVrtpn/fowNXaB6pfX1bUl4sRbGAKnF1avn4tPBAAZ5eh67bhO
JLdxTBJgqQoLePyHnb4LEPZItOUOMiHRBLUV8PSj/dxLEmYlmbPFOTnE62izRX4Q
=dM0r
-----END PGP PUBLIC KEY BLOCK-----

file that encrypted by go-openPGP can not be decrypted by GPG (Low probability

BUG info

file that encrypted by go-openPGP can not be decrypted by GPG.
file that encrypted by go-openPGP can  be decrypted by go-openPGP.
file that encrypted by PGP can  be decrypted by go-openPGP.

go (encrypt )      =>    gpg ( decrypt )  ERR
gpg (encrypt )    =>  go (decrypt )    OK
go ( encrypt)      =>   go (decrypt )    OK

this test data package have a test file that can reproduce the err

part of code


func encryptFile(t *testing.T, sourcefile, targetfile string, entity *openpgp.Entity) {
	in, err := os.Open(sourcefile)
	if err != nil {
		t.Fatal(err)
	}
	defer in.Close()
	w, err := encryptWithEntitle(t, entity, in)
	if err != nil {
		t.Fatal(err)
	}
	// defer w.Close()
	ww, err := os.Create(targetfile)
	if err != nil {
		t.Fatal(err)
	}
	defer ww.Close()
	len, err := io.Copy(ww, w)
	log.Printf("stream encrypted, len: %v", len)
	if err != nil {
		t.Fatal(err)
	}
}
func encryptWithEntitle(t *testing.T, entity *openpgp.Entity, data io.Reader) (io.Reader, error) {
	entityList := openpgp.EntityList{entity}
	buf := new(bytes.Buffer)
	wc, err := openpgp.Encrypt(buf, entityList, nil, nil, config)
	if err != nil {
		t.Errorf("encrypt err: %v", err)
		return nil, err
	}
	writelen, err := io.Copy(wc, data)
	defer wc.Close()
	t.Logf("encryptStream, len: %v, err: %v", writelen, err)
	return buf, nil
}

func TestOpenPGP_GoEncrypt_GpgDecrypt(t *testing.T) {
	entile, prikey2, err := createPgpKeyAndFile(t)
	if err != nil {
		t.Fatalf("create pgp key err: %v", err)
	}
	importKeyToKeyChain(t, fullPath(kAscName), prikey2)
	t.Log("encrypt with go openpgpg")
	encryptFile(t, fullPath(kOriginName), fullPath(kGpgName), entile)

	t.Log("decrypt with gpg")
	Run(kTestDir, "gpg", []string{"--output", kTestNewName, "--recipient", kEmail, "--decrypt", kGpgName})

	t.Log("file md5 caculating...")
	testNewNameMd5 := MD5(fullPath(kTestNewName))
	originNameMd5 := MD5(fullPath(kOriginName))

	if testNewNameMd5 != originNameMd5 {
		t.Fatalf("origin file md5 not equal the new file md5")
	}
}

gpg command line

gpg --output origin_new.png --recipient [email protected] --decrypt test.png.gpg

env information

gpg (GnuPG) 2.2.16
libgcrypt 1.8.4
mac os 10.15
go version go1.13.1 darwin/amd64

full test code:

[testdata.zip](https://github.com/ProtonMail/crypto/files/3782874/testdata.zip)

Support to allow few config changes: InsecureAllowUnauthenticatedMessages needs to be set as True & SHA1 Support

Folks, We have encountered a case where merchants are using Java SDK for PGP encryption and it has SHA1 default signature and so is the InsecureAllowUnauthenticatedMessages kept as False.

while performing decryption we are receieving Err: Insecure signature , Security wise we are not allowed to keep this value to be set as default, but the buisness requirement need this support, If we are allowed to do it I would love to add the changes.

Generated GPG Keys are no longer useable with rpm

Hi,

Due to a change in rpm "rpm-software-management/rpm@f22499a#diff-b4eac15fda646a3b73f5cd251f33387979eadc71ba52f769bd64b10bd877365cR496" it is no longer possible to use GPG keys generated by this library to sign rpm packages or metadata.

subpackets = append(subpackets, outputSubpacket{true, issuerSubpacket, true, keyId})
This sets the critical bit to true and will cause rpm to refuse the key.

Would it be possible to add a key generate option to manipulate the subpackages critical bits?

openpgp.CheckDetachedSignature failing when it was succeeding with a previous version

We use this library in rclone to validate the downloads for rclone's self update feature - thank you :-)

Unfortunately in this commit 5503f24 by @twiss openpgp.CheckDetachedSignature stopped working for us (commit found with git bisect).

commit 5503f24f010878669817f6dd4fc0d2bccd67bcd0
Author: Daniel Huigens
Date:   Tue Mar 21 16:03:18 2023 +0100

    Require key flags to use keys (#155)
    
    Don't allow using primary keys without a valid self-signature with
    key flags indicating the usage is allowed.

 openpgp/keys.go | 25 +++++++++++++------------

Reverting this commit on top of main causes openpgp.CheckDetachedSignature to work for us again.

The validation code is here: https://github.com/rclone/rclone/blob/master/cmd/selfupdate/verify.go and contains the PGP key in use.

This has worked for ages (since March 2021), first with x/crypto/pgp and then with your replacement package which we've been using since 24 June 2022 as x/crypto/pgp is no longer maintained.

Problems could be caused by:

  • The very old public PGP key that is embedded in the verify.go file.
  • The signing procedure - this is currently done with md5sum rclone-v* | gpg --clearsign > MD5SUMS

If I could fix this by updating the signatures on the server that would be perfect!

The signed messages verify with gpg if I import just that key into a new homedir and do gpg --homedir /tmp/gpg --decrypt build/MD5SUMS

Though there is a warning there - maybe that is what this is about.

gpg: Signature made Tue 17 Oct 2023 18:13:58 BST
gpg:                using DSA key FBF737ECE9F8AB18604BD2AC93935E02FF3B54FA
gpg: Good signature from "Nick Craig-Wood <[email protected]>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.

Any help appreciated!

CRUD helper functions for subpacket types 23 and 24

From the comment thread on the (similar) PR #200 :

Subpacket types 23, 24 and 31 are also conspicuously missing. It would be nice to also have these, particularly for future keyserver work but also because it should be safe in general to parse e.g. a sig with a critical "keyserver preferences" subpacket (if someone was crazy enough to do that). I'd be happy to help out with that.
A library should be able to CRUD such "user intent" subpackets. Beyond that I think it's entirely an application issue.

For reference, these subpacket types are:

  • 23 - Key Server Preferences (N octets of flags)
  • 24 - Preferred Key Server (String, to be interpreted as a URI)
  • 31 - Signature Target (1 octet public-key algorithm, 1 octet hash algorithm, N octets hash)

No processing of these values is required at the library level, however the application layer should have the ability to CRUD these subpackets, and the library layer should pass them through gracefully.

Note that it is an open question whether type 31 is useful (see https://gitlab.com/dkg/openpgp-revocation/-/issues/13), so I suggest only implementing types 23 and 24 at this time.


bitLength not correct, and ECDH privateKey load with GPG is wrong

Hi
there are two bugs in this test case
1: bitlength error, when i generate entity with EdDSA, and the subkey bitlength is wrong. its 263, not 256
2: ouput this key to one asc file, and then , import the file with "gpg --import", its wrong. public key is ok, primary key is error
i tested ouput with password, and without password, it all wrong.
ONLY WITH ECDH

main test funcation

func TestOpenPGP_ExportECDH_GPGImport(t *testing.T) {
	entity, err := openpgp.NewEntity("name", "comment", "[email protected]", config)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	bitlen, err := entity.Subkeys[0].PublicKey.BitLength()
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if bitlen != 256 {
		t.Logf("!!! ERROR bitlen: %v: \n", bitlen)
	}

	pgpg, _ := exportGPG(entity)
	t.Fatalf("!!! ERROR, gpg --import with this file will ERROR: \n%v", pgpg)
}

ENV

go version go1.13.1 darwin/amd64
gpg (GnuPG) 2.2.16
libgcrypt 1.8.4
mac10.15

openpgp_test.go.zip

cloudflare/circl dependency makes it difficult to compile without cgo for amd64

I initially reported this in google/go-github#2932 but it is also relevant here depending on how you intend this library to be used (with our without cgo).

I'm running into a slightly obscure build problem. Using bazel (and gazelle and rules_go) to build worked fine both for arm64 and amd64. I recently tried to bump to a package which uses go-crypto as a dependency and found myself unable to build for amd64 via bazel.

The dependency github.com/cloudflare/circl was bumped from v1.1.0 to v1.3.3. The problem is that it includes some platform specific files changes (*_amd64.go) for some packages, some headers and some assembly. It's not new but some changes seem to have been introduced which changed the behavior of the build.

Unfortunately led to some issues trying to build via bazel with dependencies not detected:

external/com_github_cloudflare_circl/dh/x25519/curve_amd64.s:7: #include: open external/com_github_cloudflare_circl/math/fp25519/fp_amd64.h: no such file or directory

From what I can tell it would be possible to specify the purego build tag to avoid this behavior but it's a bit cumbersome to use a manual rather than the cgo builtin tag.

Requests from Feng & Kay

  • Move code that disallows verification/encryption with expired keys from go-pmapi -> crypto library

  • Allow private and public keys to be passed in separately in Read.go (line 86)

Older versions of this library throw: unknown critical signature subpacket type 33

We are happy to answer your questions about the code or discuss technical ideas.

Please complete the following checklist (by adding [x]):

  • [x ] I have searched open and closed issues for duplicates
  • [x ] This isn't a feature request
  • [x ] This is not a report about my app not working as expected

As of #58, older version of this module are no longer able to verify the signatures this module produces. This is a problem because we're using this library to sign releases. When older versions download their updates, they verify using the signature with this library.

The problem seems to be related to this comment:

Also, add support for the Issuer Fingerprint subpacket, and generate it for
all signatures (both V4 and V5).

The older versions of this library don't recognise this new subpacket and consider that a critical failure. I'm not intimately familiar with ssl, but would it make sense to only add the issuer fingerprint subpacket for v5?

Index out of range error at copyReversed function

Sometimes getting this:

goroutine 295 [running]:
net/http.(*conn).serve.func1(0xc0000b5a40)
	/usr/lib/golang/src/net/http/server.go:1769 +0x139
panic(0x8a1a80, 0xd9d180)
	/usr/lib/golang/src/runtime/panic.go:522 +0x1b5
golang.org/x/crypto/openpgp/ecdh.copyReversed(0xc0008431b0, 0x20, 0x20, 0xc0006ea5c0, 0x1f, 0x1f)
	/home/savely/go/pkg/mod/github.com/!proton!mail/[email protected]/openpgp/ecdh/x25519.go:144 +0x112
golang.org/x/crypto/openpgp/ecdh.X25519Decrypt(0xc00045ede0, 0xc0003a8b10, 0x21, 0x21, 0xc0003a8b40, 0x30, 0x30, 0xc000785420, 0xb, 0x10, ...)
	/home/savely/go/pkg/mod/github.com/!proton!mail/[email protected]/openpgp/ecdh/x25519.go:112 +0x17a
golang.org/x/crypto/openpgp/ecdh.Decrypt(0xc00045ede0, 0xc0003a8b10, 0x21, 0x21, 0xc0003a8b40, 0x30, 0x30, 0xc000785420, 0xb, 0x10, ...)
	/home/savely/go/pkg/mod/github.com/!proton!mail/[email protected]/openpgp/ecdh/ecdh.go:91 +0x4a1
golang.org/x/crypto/openpgp/packet.(*EncryptedKey).Decrypt(0xc00017eaf0, 0xc00018fe00, 0xc0002f02a0, 0x0, 0x0)
	/home/savely/go/pkg/mod/github.com/!proton!mail/[email protected]/openpgp/packet/encrypted_key.go:111 +0x4e8
golang.org/x/crypto/openpgp.ReadMessage(0x9c63e0, 0xc0002c0870, 0x9cf520, 0xc00068ec20, 0x0, 0xc0002f02a0, 0x1, 0x1, 0xc0002c0870)
	/home/savely/go/pkg/mod/github.com/!proton!mail/[email protected]/openpgp/read.go:161 +0xca3
github.com/ProtonMail/gopenpgp/crypto.asymmetricDecrypt(0x9c63e0, 0xc0002c0870, 0xc0003001e0, 0xc0003bbf20, 0x5d1b3ec9, 0xc01b418690, 0x58789950045dd, 0xc000843860, 0x7c931f, 0xbf3eed925b418690, ...)
	/home/savely/go/pkg/mod/github.com/!proton!mail/[email protected]/crypto/keyring_message.go:140 +0x1b3
github.com/ProtonMail/gopenpgp/crypto.(*KeyRing).Decrypt(0xc0003001e0, 0xc00068ec00, 0xc0003bbf20, 0x5d1b3ec9, 0x0, 0x0, 0xc000843900, 0x448ac0)
	/home/savely/go/pkg/mod/github.com/!proton!mail/[email protected]/crypto/keyring_message.go:40 +0xe2

Function itself:

func copyReversed(out []byte, in []byte) {
	for i := 31; i >= 0; i-- {
		out[31-i] = in[i]
	}
}

Sometimes in length is 31.

Backwards-compatible packet serializer

Currently, go-crypto/openpgp only supports new-format packet headers on output, but both old and new formats on input (RFC4880 §4.2). This is entirely in line with the SHOULD provisions of that section, however there are use cases where the ability to produce old-format headers may be desirable.

I have implemented this already in a draft PR to hockeypuck (hockeypuck/hockeypuck#190), but the code would be much cleaner (and smaller!) if it could be implemented here instead. Obviously this increases maintenance costs very slightly, but the logic is well-understood and already implemented here for input.

The calling application would have to specifically invoke the compatibility serializer, so existing dependent code will not be affected.

VerifyRevocationSignature is misnamed

(PublicKey)VerifyRevocationSignature appears also to be able to verify any direct signature. Is this intentional? And can I rely on it always working for direct certifications? :-)

Error in workflow when encrypting private key to be exported

  1. What version of Go are you using (go version)?
    go version go1.14.2 darwin/amd64

  2. What operating system and processor architecture are you using?
    Testing purposes on a MacBook Pro (darwin/amd64)

  3. What did you do?
    Trying to migrate from x/crypto/openpgp to ProtonMail/crypto/openpgp to enable exporting generated PGP key with private key encrypted with passphrase. Test code is in https://gist.github.com/jbouse/86957f5e7bd44337eeccf9d705d54c55

  4. What did you expect to see?
    I expect to see a single log output stating:
    2020/05/13 14:45:00 Encrypted: true
    I also expect to see 2 files created testkey.asc and testkey.pub.asc with the encrypted private and the public key respectively.

  5. What did you see instead?
    I get the expected log output and the testkey.pub.asc contains the expected public key; however, the testkey.asc file is prematurely closed and I receive the following panic message output:

panic: interface conversion: interface is nil, not crypto.Signer

goroutine 1 [running]:
golang.org/x/crypto/openpgp/packet.(*Signature).Sign(0xc000150000, 0x11aa9c0, 0xc000164200, 0xc0003e0000, 0x0, 0xc000164200, 0x0)
        /Users/JeremyBouse/go/pkg/mod/github.com/!proton!mail/[email protected]/openpgp/packet/signature.go:564 +0x14c
golang.org/x/crypto/openpgp/packet.(*Signature).SignUserId(0xc000150000, 0xc000016260, 0x1e, 0xc0003e40e0, 0xc0003e0000, 0x0, 0x15, 0x20)
        /Users/JeremyBouse/go/pkg/mod/github.com/!proton!mail/[email protected]/openpgp/packet/signature.go:635 +0xca
golang.org/x/crypto/openpgp.(*Entity).serializePrivate(0xc000066190, 0x13a22a8, 0xc000066280, 0x0, 0x1152d01, 0x0, 0x13a22a8)
        /Users/JeremyBouse/go/pkg/mod/github.com/!proton!mail/[email protected]/openpgp/keys.go:537 +0x1df
golang.org/x/crypto/openpgp.(*Entity).SerializePrivate(0xc000066190, 0x13a22a8, 0xc000066280, 0x0, 0xc000066280, 0x11a9640)
        /Users/Jere:511 +0x67
main.encodePrivateKey(0x11a9040, 0xc00000e0a8, 0xc000066190)
        /Users/JeremyBouse/Git/poc/main.go:43 +0x181
main.generateKeys(0x1179fea, 0x8, 0x117c084, 0x13)
        /Users/JeremyBouse/Git/poc/main.go:80 +0x4a6
main.main()
        /Users/JeremyBouse/Git/poc/main.go:34 +0x4b

If however, I comment out lines 74-77 of the gist main.go file and rebuild then it executes fine without the panic but the private key is not encrypted with a passphrase and the log output instead reports as expected:
2020/05/13 15:04:52 Encrypted: false

For debugging I've let it use the safe default packet.Config and set the parameter to nil rather than use the config variable that was defined to make sure that wasn't the cause for issue. Am I missing a step or performing something incorrectly or is there an issue within the entity.SerializePrivate function when the key is encrypted?

AEAD Encrypt fails for long plaintexts

Current bug behavior

The message encrypting function openpgp.Encrypt panics on Write for long plaintext messages.
When calling openpgp.Encrypt on plaintexts of length around 1<<20, EndToEndTest fails with

	panic: bytes.Buffer.WriteTo: invalid Write count

(see the whole stack trace below)

Expected behavior

TestEndToEnd should be able to encrypt messages of this size and larger.

How to reproduce

Go to openpgp/integration_tests/utils_test.go function randMessage() and increase the size of random test messages:

	maxMessageLength := 1 << 20

(previous value set at 1 << 12), and run the test:

go test ./... -run EndToEnd

Posible cause

Definitely related to AEADEncrypted writer or closer, according to the stack trace, which is in turn related to the implementation of partialLengthWriter. The panic arises when closing a partialLengthWriter.

Also, there's no panic if AEAD is disabled (indicated by the absence of a packet.AEADConfig inside the packet.Config passed to openpgp.Encrypt).

Posible fix

WIP

Related PRs

#36 - Aead packet support.

Complete traceback

=== RUN   TestEndToEnd/rsa_foreign/encryptDecrypt/ed25519_fresh
panic: bytes.Buffer.WriteTo: invalid Write count [recovered]
	panic: bytes.Buffer.WriteTo: invalid Write count

goroutine 69 [running]:
testing.tRunner.func1(0xc0000b6500)
	/usr/local/go/src/testing/testing.go:874 +0x3a3
panic(0x600d00, 0x691f40)
	/usr/local/go/src/runtime/panic.go:679 +0x1b2
bytes.(*Buffer).WriteTo(0xc0000749d0, 0x7fbf723016b8, 0xc00004a210, 0x7fbf723016b8, 0xc00004a210, 0xc00032a4e0)
	/usr/local/go/src/bytes/buffer.go:241 +0x145
golang.org/x/crypto/openpgp/packet.(*partialLengthWriter).Close(0xc0000749c0, 0x69a180, 0xc00007a000)
	/home/botvinnik/go/src/golang.org/x/crypto/openpgp/packet/packet.go:135 +0xd5
golang.org/x/crypto/openpgp.signatureWriter.Close(0x698000, 0xc0000a2280, 0x698040, 0xc0000749c0, 0x5, 0x69a180, 0xc00007a000, 0x69a180, 0xc00007a000, 0xc000001c80, ...)
	/home/botvinnik/go/src/golang.org/x/crypto/openpgp/write.go:462 +0x140
golang.org/x/crypto/openpgp/integration_tests.encDecTest.func1(0xc0000b6500)
	/home/botvinnik/go/src/golang.org/x/crypto/openpgp/integration_tests/end_to_end_test.go:175 +0x3e2
testing.tRunner(0xc0000b6500, 0xc00031a000)
	/usr/local/go/src/testing/testing.go:909 +0xc9
created by testing.(*T).Run
	/usr/local/go/src/testing/testing.go:960 +0x350
exit status 2
FAIL	golang.org/x/crypto/openpgp/integration_tests	1.393s

Feature request: Support to wrap pre-created RSA, ECDSA or Ed25519 keys

Context

There are use cases where keys are pre-created. For example, on environments where key derivations are required.

The function NewEntity can only be used to create keys from scratch based on parameters passed on the config, and does not allow passing pre-created keys.

Solution

In the PR #201, I've created a new function NewEntityFromKey so that users can pass pre-created keys of types *rsa.PrivateKey, *ecdsa.PrivateKey and ed25519.PrivateKey (not a pointer).

I copied the latter assumptions from the package x509 (for instance function MarshalPKCS8PrivateKey), looks like it is being a convention in the Go standard libraries to pass around ed25519.PrivateKey and ed25519.PublicKey keys without pointers.

This is a proof the entity created from passed keys works with gpg: https://gist.github.com/balena/27ef6b7ca319cd43f0d2d9ff2af49248
(run with go test -v -count=1 .)

Armor decoding fails for malformed(?) headers

Hi guys, I need to work with an external service, who's PGP detached signature includes a line Version: as a header, with no space or no value (just a newline after it).

As per section 6.2 of RFC 4880, quote:

The format of an Armor Header is that of a key-value pair. A colon
(':' 0x38) and a single space (0x20) separate the key and value.
OpenPGP should consider improperly formatted Armor Headers to be
corruption of the ASCII Armor. Unknown keys should be reported to
the user, but OpenPGP should continue to process the message.

Indeed, if I use gpg to try and verify such a signature, it works.

Plaintext signature, hexdump, and gpg verification passing
$ cat signature.asc
-----BEGIN PGP SIGNATURE-----
Version:

iQEzBAABCAAdFiEEoSOgqNCnAp+EumHncWO0DMTgrJ8FAmSL6xMACgkQcWO0DMTg
rJ8KrQf6A5AgMpGyekIiBeG2lPeqe5PIulKBI0kHDo01ofXt31ahnVrQmfHw7AMc
sHLk3LkS85aR2pU8M1+NY4vc7TBQszwyCILKxOV43hCXmxMlhEuNsARJ/MOWmdfd
dQaFSmx9doXeKtHU6xO0sWrMFgj69rnH9Q4ZvvqrrLkVEHpMJar0xPNGVZyegZ8h
arlmBseDFHavcdmhrcxUt0ry0IITTu0NBzRnyZB40e01jnzCVHQiGeitgCuTFh4r
NJGg9zRmWUpKTIVl7upSds9SiaVEJLfJPG/oDSTOJDyJBR7sKcJ/4z2OemRK89Ft
JX24K2nnjlT5RNxSTF0lQ8auQXhmRQ==
=nQKz
-----END PGP SIGNATURE-----

$ xxd signature.asc
00000000: 2d2d 2d2d 2d42 4547 494e 2050 4750 2053  -----BEGIN PGP S
00000010: 4947 4e41 5455 5245 2d2d 2d2d 2d0a 5665  IGNATURE-----.Ve
00000020: 7273 696f 6e3a 0a0a 6951 457a 4241 4142  rsion:..iQEzBAAB
00000030: 4341 4164 4669 4545 6f53 4f67 714e 436e  CAAdFiEEoSOgqNCn
00000040: 4170 2b45 756d 486e 6357 4f30 444d 5467  Ap+EumHncWO0DMTg
00000050: 724a 3846 416d 534c 3678 4d41 4367 6b51  rJ8FAmSL6xMACgkQ
00000060: 6357 4f30 444d 5467 0a72 4a38 4b72 5166  cWO0DMTg.rJ8KrQf
00000070: 3641 3541 674d 7047 7965 6b49 6942 6547  6A5AgMpGyekIiBeG
00000080: 326c 5065 7165 3550 4975 6c4b 4249 306b  2lPeqe5PIulKBI0k
00000090: 4844 6f30 316f 6658 7433 3161 686e 5672  HDo01ofXt31ahnVr
000000a0: 516d 6648 7737 414d 630a 7348 4c6b 334c  QmfHw7AMc.sHLk3L
000000b0: 6b53 3835 6152 3270 5538 4d31 2b4e 5934  kS85aR2pU8M1+NY4
000000c0: 7663 3754 4251 737a 7779 4349 4c4b 784f  vc7TBQszwyCILKxO
000000d0: 5634 3368 4358 6d78 4d6c 6845 754e 7341  V43hCXmxMlhEuNsA
000000e0: 524a 2f4d 4f57 6d64 6664 0a64 5161 4653  RJ/MOWmdfd.dQaFS
000000f0: 6d78 3964 6f58 654b 7448 5536 784f 3073  mx9doXeKtHU6xO0s
00000100: 5772 4d46 676a 3639 726e 4839 5134 5a76  WrMFgj69rnH9Q4Zv
00000110: 7671 7272 4c6b 5645 4870 4d4a 6172 3078  vqrrLkVEHpMJar0x
00000120: 504e 4756 5a79 6567 5a38 680a 6172 6c6d  PNGVZyegZ8h.arlm
00000130: 4273 6544 4648 6176 6364 6d68 7263 7855  BseDFHavcdmhrcxU
00000140: 7430 7279 3049 4954 5475 304e 427a 526e  t0ry0IITTu0NBzRn
00000150: 795a 4234 3065 3031 6a6e 7a43 5648 5169  yZB40e01jnzCVHQi
00000160: 4765 6974 6743 7554 4668 3472 0a4e 4a47  GeitgCuTFh4r.NJG
00000170: 6739 7a52 6d57 5570 4b54 4956 6c37 7570  g9zRmWUpKTIVl7up
00000180: 5364 7339 5369 6156 454a 4c66 4a50 472f  Sds9SiaVEJLfJPG/
00000190: 6f44 5354 4f4a 4479 4a42 5237 734b 634a  oDSTOJDyJBR7sKcJ
000001a0: 2f34 7a32 4f65 6d52 4b38 3946 740a 4a58  /4z2OemRK89Ft.JX
000001b0: 3234 4b32 6e6e 6a6c 5435 524e 7853 5446  24K2nnjlT5RNxSTF
000001c0: 306c 5138 6175 5158 686d 5251 3d3d 0a3d  0lQ8auQXhmRQ==.=
000001d0: 6e51 4b7a 0a2d 2d2d 2d2d 454e 4420 5047  nQKz.-----END PG
000001e0: 5020 5349 474e 4154 5552 452d 2d2d 2d2d  P SIGNATURE-----
000001f0: 0a                                       .

$ gpg --verify signature.asc plaintext.txt
gpg: WARNING: unsafe permissions on homedir '/home/raghu/Documents/gitops/applications/common-go/pgp'
gpg: Signature made Fri 16 Jun 2023 12:54:43 PM HKT
gpg:                using RSA key A123A0A8D0A7029F84BA61E77163B40CC4E0AC9F
gpg: Good signature from "Alice (Alice for Unit Test) <[email protected]>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: A123 A0A8 D0A7 029F 84BA  61E7 7163 B40C C4E0 AC9F

However due to how this library is currently implementing armored decoding, it will fail, because when it finds a non empty line immediately after the initial header (without a double newline, i.e. \n\n) , it will try and parse it as a header as well. If this fails, it will skip everything it did so far, and jump to the start of the function, to try and find a new block from the next line onwards .

Would you guys be open to accepting an MR which fixes this behavior? i.e. to ignore such header lines and proceed with decoding the rest of it.

The buggy part:

i := bytes.Index(line, []byte(": "))
if i == -1 {
goto TryNextBlock
}

openpgp: unsupported feature: unknown critical signature subpacket type 5

We are happy to answer your questions about the code or discuss technical ideas.

Please complete the following checklist (by adding [x]):

  • I have searched open and closed issues for duplicates
  • This isn't a feature request
  • This is not a report about my app not working as expected

go-crypto inherited golang.org/x/crypto/openpgp's lack of support for certain signature subpackets, as reported in golang/go#20686. As a consequence, some public keys are completely unusable by the library. The testcase in the linked issue can be used to reproduce it on go-crypto by changing the import.

Tests fail on ppc64el with panic: runtime error: invalid memory address or nil pointer dereference [recovered]

We are happy to answer your questions about the code or discuss technical ideas.

Please complete the following checklist (by adding [x]):

  • I have searched open and closed issues for duplicates
  • This isn't a feature request
  • This is not a report about my app not working as expected

Some tests are failing on ppc64el architecture.

=== RUN   TestP256t1
--- FAIL: TestP256t1 (0.00s)
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
	panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x30 pc=0x11694c]

goroutine 18 [running]:
testing.tRunner.func1.2({0x142a00, 0x246950})
	/usr/lib/go-1.17/src/testing/testing.go:1209 +0x27c
testing.tRunner.func1(0xc000083380)
	/usr/lib/go-1.17/src/testing/testing.go:1212 +0x228
panic({0x142a00, 0x246950})
	/usr/lib/go-1.17/src/runtime/panic.go:1038 +0x240
crypto/elliptic.matchesSpecificCurve(0xc0000ac6c0, {0xc00009add0, 0x3, 0x3})
	/usr/lib/go-1.17/src/crypto/elliptic/elliptic.go:45 +0x7c
crypto/elliptic.(*CurveParams).ScalarBaseMult(0xc0000ac6c0, {0xc0000e2020, 0x20, 0x20})
	/usr/lib/go-1.17/src/crypto/elliptic/elliptic.go:313 +0xbc
crypto/ecdsa.GenerateKey({0x1901c0, 0xc0000ac6c0}, {0x18d3c0, 0xc0000a21e0})
	/usr/lib/go-1.17/src/crypto/ecdsa/ecdsa.go:158 +0x168
github.com/ProtonMail/go-crypto/brainpool.testCurve(0xc000083380, {0x1901c0, 0xc0000ac6c0})
	/tmp/autopkgtest-lxc.bl6ydmwq/downtmp/autopkgtest_tmp/_build/src/github.com/ProtonMail/go-crypto/brainpool/brainpool_test.go:11 +0x50
github.com/ProtonMail/go-crypto/brainpool.TestP256t1(0xc000083380)
	/tmp/autopkgtest-lxc.bl6ydmwq/downtmp/autopkgtest_tmp/_build/src/github.com/ProtonMail/go-crypto/brainpool/brainpool_test.go:28 +0x80
testing.tRunner(0xc000083380, 0x1687f8)
	/usr/lib/go-1.17/src/testing/testing.go:1259 +0xf0
created by testing.(*T).Run
	/usr/lib/go-1.17/src/testing/testing.go:1306 +0x370
FAIL	github.com/ProtonMail/go-crypto/brainpool	0.011s

Full log at https://ci.debian.net/data/autopkgtest/testing/ppc64el/g/golang-github-protonmail-go-crypto/16755345/log.gz

Required Key Flags Breaking Workflows

👋 Hello folks! I want to start by saying I really appreciate the existence of this library and the dedication here to trying to do the right thing.

I wanted to flag that I believe #155 has some unintended consequences and could use a bit more discussion.

We regularly exchange OpenPGP keys with third-party institutions and we we still see on occasion that keys are being created without flags indicating the proper usage. I'm not exactly sure where these keys come from, but they are out there in the wild. Often we do not have the ability to request new signatures on these keys, especially as these keys will work with gpg, which is seen as somewhat of a reference implementation.

Since the change was made on this library, we switched to modifying the key structs after parsing to manually mark them as valid, which is viable, but requires us to keep track of keys we expect to have no flags.

I do wish the RFC was stronger on this topic.

On the other hand, the "communications encryption" flag in a self-signature is stating a preference that a given key be used for communications.

I have (questionably) interpreted that as the flags being optional (indicating a preference) rather than a requirement. But I am open to other interpretations.

(#187 was opened by another user, but it seems that in their case they were able to modify the key.)

Add `crypto/x509` to this repo

Right now we are not able to test go test ./openpgp/packet/

# golang.org/x/crypto/openpgp/packet [golang.org/x/crypto/openpgp/packet.test]
openpgp/packet/private_key_test.go:132:37: cannot use rsaPriv (type *"crypto/rsa".PrivateKey) as type *"golang.org/x/crypto/rsa".PrivateKey in argument to NewRSAPrivateKey
openpgp/packet/private_key_test.go:224:33: not enough arguments in call to "golang.org/x/crypto/rsa".GenerateKey
        have (io.Reader, number)
        want (io.Reader, int, []*big.Int)
FAIL    golang.org/x/crypto/openpgp/packet [build failed]

even though this two classes have same structure go treat them as two uniq types.

Re-introduce "support" for decrypting messages without MDC

For a while now (~2018), the decryption of symmetrically encrypted packets without MDC (Tag 9) has been disabled.

While this follows the recommendation in the current IETF Crypto Refresh Draft, it can cause problems when interacting with old clients. I think it's valid to block these interactions by default, but would like to propose offering an opening for cases where this can't be avoided.

An easy possible fix might be to introduce a package wide global variable that toggles support for MDC (and defaults to "not allowed"). When set to "allowed", this check would be rendered ineffective.

I would even more prefer the ability to decide about this on a per-decryption basis (vs a global variable), but at the point where this check is made, there is no access to any configuration passed from the outside and refactoring that would probably not be worth it for such a fringe case.

WDYT about allowing decryption of messages without MDC again (via opt-in)?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.