ProtonMail/go-crypto

Error in workflow when encrypting private key to be exported

jbouse opened this issue · 4 comments

  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/crypto@v0.0.0-20200416114516-1fa7f403fb9c/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/crypto@v0.0.0-20200416114516-1fa7f403fb9c/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/crypto@v0.0.0-20200416114516-1fa7f403fb9c/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?

twiss commented

Hey 👋 Try using SerializePrivateWithoutSigning instead of SerializePrivate. SerializePrivate always tries to re-sign the key, which is impossible when it's encrypted.

@twiss I'll try that and see if it helps solve the problem. Thank you.

Okay so changing SerializePrivate to SerializePrivateWithoutSigning solved the issue and appears to be working as expected now. Of note this method does not appear to be shown on the documentation I saw on https://pkg.go.dev/github.com/ProtonMail/crypto@v2.0.0+incompatible/openpgp?tab=doc where I was reading from so maybe this is a recent change? I had tried the SerializePrivateNoSign as the doc page had but it had failed stating method didn't exist.

twiss commented

Yeah, we recently changed this indeed. Sorry about that!