ProtonMail / gopenpgp

A high-level OpenPGP library
https://gopenpgp.org
MIT License
1.06k stars 116 forks source link

Cannot specify filename when encrypting + signing #289

Open WordsmithCreativity opened 4 months ago

WordsmithCreativity commented 4 months ago

In both v2 and v3 of the library there is no possibility to specify a filename when both signing and encrypting a file.

This would mimic the behavior of gpg as such:

$ gpg --encrypt --sign -r XXX test.txt
$ gpg --list-packets test.txt.gpg
...
:literal data packet:
    mode b (62), created 1721297550, name="test.txt",
    raw data: 9 bytes
...
:signature packet: algo 1, keyid XXX
...

I've altered the https://github.com/ProtonMail/gopenpgp/blob/main/helper/sign_detached.go#L14 function slightly to allow my use-case as such:

func SignAndEncryptWithFileName(publicKey string, privateKey string, passphrase []byte, plaintext string, filename string) (string, error) {
    var privateKeyObj, unlockedKeyObj *crypto.Key
    var publicKeyRing, privateKeyRing *crypto.KeyRing
    var pgpMessage *crypto.PGPMessage
    var ciphertext string

    var message = crypto.NewPlainMessageFromFile([]byte(plaintext), filename, uint32(crypto.GetUnixTime()))

    publicKeyObj, err := crypto.NewKeyFromArmored(publicKey)
    if err != nil {
        return "", err
    }

    publicKeyRing, err = crypto.NewKeyRing(publicKeyObj)
    if err != nil {
        return "", err
    }

    if privateKeyObj, err = crypto.NewKeyFromArmored(privateKey); err != nil {
        return "", errors.New("gopenpgp: unable to read key")
    }

    if unlockedKeyObj, err = privateKeyObj.Unlock(passphrase); err != nil {
        return "", errors.New("gopenpgp: unable to unlock key")
    }
    defer unlockedKeyObj.ClearPrivateParams()

    if privateKeyRing, err = crypto.NewKeyRing(unlockedKeyObj); err != nil {
        return "", errors.New("gopenpgp: unable to create new keyring")
    }

    if pgpMessage, err = publicKeyRing.Encrypt(message, privateKeyRing); err != nil {
        return "", errors.New("gopenpgp: unable to encrypt message")
    }

    if ciphertext, err = pgpMessage.GetArmored(); err != nil {
        return "", errors.New("gopenpgp: unable to armor ciphertext")
    }

    return ciphertext, nil
}

Can this be made possible via the exposed functions?

inputvalidation commented 2 months ago

I'm also experiencing this issue, any chance this could be implemented? Or do you otherwise welcome a PR to introduce this?

clncy commented 1 month ago

+1 I'm also interested in this feature

inputvalidation commented 5 days ago

I'm also experiencing this issue, any chance this could be implemented? Or do you otherwise welcome a PR to introduce this?

I would appreciate some feedback on this if you have a minute?

lubux commented 5 days ago

Hi 👋 The name field in the literal data packet is not included in signatures and ,thus, is malleable. GopenPGP follows RFC 9580's recommendation:

It SHOULD set the filename to the empty string (encoded as a single zero octet) and the timestamp to zero (encoded as four zero octets).