skeeto / passphrase2pgp

Generate a PGP key from a passphrase
The Unlicense
187 stars 14 forks source link

passforios works with gpg-generated keys, but not passphrase2pgp ones #5

Open jakajancar opened 4 years ago

jakajancar commented 4 years ago

See https://github.com/mssun/passforios/issues/318. Likely a bug there, but something is different between the keys that makes one work but not the other one.

The only difference I can see is the Authentication usage, but that shouldn't matter.

Key generated by passphrase2pgp (not working):

sec  ed25519/A0F42AA25ECE82CF
     created: 1970-01-01  expires: never       usage: SCA 
     trust: ultimate      validity: ultimate
ssb  cv25519/DCFD5B0A1DF33E4F
     created: 1970-01-01  expires: never       usage: E   
[ultimate] (1). Jaka Jancar <jaka@kubje.org>

Key generated by gpg (working):

sec  ed25519/0564372101766863
     created: 2019-10-04  expires: never       usage: SC  
     trust: ultimate      validity: ultimate
ssb  cv25519/72759FECE62D9A8E
     created: 2019-10-04  expires: never       usage: E   
[ultimate] (1). Jaka Jancar <jaka@kubje.org>
jakajancar commented 4 years ago

They also have differing packets and subpackets:

passphrase2pgp (not working):

# off=0 ctb=94 tag=5 hlen=2 plen=88
:secret key packet:
    version 4, algo 22, created 0, expires 0
    pkey[0]: [80 bits] ed25519 (1.3.6.1.4.1.11591.15.1)
    pkey[1]: [263 bits]
    skey[2]: [255 bits]
    checksum: 1155
    keyid: A0F42AA25ECE82CF
# off=90 ctb=b4 tag=13 hlen=2 plen=28
:user ID packet: "Jaka Jancar <jaka@kubje.org>"
# off=120 ctb=88 tag=2 hlen=2 plen=100
:signature packet: algo 22, keyid A0F42AA25ECE82CF
    version 4, created 0, md5len 0, sigclass 0x13
    digest algo 8, begin of digest 2f 64
    hashed subpkt 2 len 4 (sig created 1970-01-01)
    hashed subpkt 16 len 8 (issuer key ID A0F42AA25ECE82CF)
    hashed subpkt 27 len 1 (key flags: 03)
    hashed subpkt 30 len 1 (features: 01)
    data: [255 bits]
    data: [255 bits]
# off=222 ctb=9c tag=7 hlen=2 plen=93
:secret sub key packet:
    version 4, algo 18, created 0, expires 0
    pkey[0]: [88 bits] cv25519 (1.3.6.1.4.1.3029.1.5.1)
    pkey[1]: [263 bits]
    pkey[2]: [32 bits]
    skey[3]: [255 bits]
    checksum: 1065
    keyid: DCFD5B0A1DF33E4F
# off=317 ctb=88 tag=2 hlen=2 plen=97
:signature packet: algo 22, keyid A0F42AA25ECE82CF
    version 4, created 0, md5len 0, sigclass 0x18
    digest algo 8, begin of digest ff 1a
    hashed subpkt 2 len 4 (sig created 1970-01-01)
    hashed subpkt 16 len 8 (issuer key ID A0F42AA25ECE82CF)
    hashed subpkt 27 len 1 (key flags: 0C)
    data: [255 bits]
    data: [256 bits]

gpg (working):

# off=0 ctb=94 tag=5 hlen=2 plen=87
:secret key packet:
    version 4, algo 22, created 1570193808, expires 0
    pkey[0]: [80 bits] ed25519 (1.3.6.1.4.1.11591.15.1)
    pkey[1]: [263 bits]
    skey[2]: [248 bits]
    checksum: 11d9
    keyid: 0564372101766863
# off=89 ctb=b4 tag=13 hlen=2 plen=28
:user ID packet: "Jaka Jancar <jaka@kubje.org>"
# off=119 ctb=88 tag=2 hlen=2 plen=144
:signature packet: algo 22, keyid 0564372101766863
    version 4, created 1570193808, md5len 0, sigclass 0x13
    digest algo 8, begin of digest 3e 81
    hashed subpkt 33 len 21 (issuer fpr v4 9524727D0EF453D57F1A881E0564372101766863)
    hashed subpkt 2 len 4 (sig created 2019-10-04)
    hashed subpkt 27 len 1 (key flags: 03)
    hashed subpkt 11 len 4 (pref-sym-algos: 9 8 7 2)
    hashed subpkt 21 len 5 (pref-hash-algos: 10 9 8 11 2)
    hashed subpkt 22 len 3 (pref-zip-algos: 2 3 1)
    hashed subpkt 30 len 1 (features: 01)
    hashed subpkt 23 len 1 (keyserver preferences: 80)
    subpkt 16 len 8 (issuer key ID 0564372101766863)
    data: [256 bits]
    data: [253 bits]
# off=265 ctb=9c tag=7 hlen=2 plen=93
:secret sub key packet:
    version 4, algo 18, created 1570193808, expires 0
    pkey[0]: [88 bits] cv25519 (1.3.6.1.4.1.3029.1.5.1)
    pkey[1]: [263 bits]
    pkey[2]: [32 bits]
    skey[3]: [255 bits]
    checksum: 127a
    keyid: 72759FECE62D9A8E
# off=360 ctb=88 tag=2 hlen=2 plen=120
:signature packet: algo 22, keyid 0564372101766863
    version 4, created 1570193808, md5len 0, sigclass 0x18
    digest algo 8, begin of digest 76 29
    hashed subpkt 33 len 21 (issuer fpr v4 9524727D0EF453D57F1A881E0564372101766863)
    hashed subpkt 2 len 4 (sig created 2019-10-04)
    hashed subpkt 27 len 1 (key flags: 0C)
    subpkt 16 len 8 (issuer key ID 0564372101766863)
    data: [256 bits]
    data: [255 bits]
skeeto commented 4 years ago

I have a few ideas of what might be going wrong.

1) Perhaps passforios doesn't properly handle keys with zero dates (1970-01-01). I've found that both GnuPG and Keybase have issues with zero dates:

https://dev.gnupg.org/T4670 https://github.com/keybase/keybase-issues/issues/3484

To test this, see if the problem persists with a non-zero date. Do everything the same, but when generating the key use --time (-t) with a non-zero argument such as 1. Note: They key material will be identical, but the fingerprint will change since it incorporates the creation date.

2) What version of GnuPG does passforios use? The new OpenPGP standard (4880bis) still isn't finalized, and Ed25519 keys are a relatively new feature (GnuPG 2.1.0, November 2014). RedHat didn't even start supporting such keys until a few months ago. Perhaps passforios uses an older version of GnuPG and fails to import the keys.

To remove passforios from the loop, in addition to knowing its version of GnuPG, I'd like to see the exact gpg commands it's running to get that error. When GnuPG says "No secret key" it doesn't always mean there's no secret key. If the key is protected by a passphrase, and it failed to prompt for that passphrase, it gives the same error message (rather than something more relevant). This can easily happen when gpg is used in an automated way with --batch (via script, etc.) and standard input/output has been redirected:

https://dev.gnupg.org/T4677

If you're using passphrase protection via --protect (-e), see if the bug persists when you omit that option. This will avoid pinentry failures that result in "No secret key."

3) If you look carefully at the packet listing you might notice that passphrase2pgp doesn't output a "hashed subpkt 33". This is intentional since that subpacket is optional, and, for self-signatures, entirely redundant and unnecessary. Leaving it out shaves off 22 bytes (and more when armored) making the key smaller. I'm not aware of an implementation refusing to import a key lacking this subpacket. Since passforios farms the work out to GnuPG, it's unlikely this is the issue.

jakajancar commented 4 years ago

Tried and adding a date does not help.

passforios doesn't use GPG but https://github.com/krzyzanowskim/ObjectivePGP

I'm not using passphrase protection anywhere.

Keep in mind it's not a problem to import keys. Keys are in passforios and on my mac.

Encrypted on mac -> can be decrypted in passforios Encrypted on passforios -> CANNOT be decrypted on mac

So problem is (I guess?) in encryption.

jakajancar commented 4 years ago

Actually I'm not sure if they use ObjectivePGP or gopenpgp, both seems to be referenced in the source code.

jakajancar commented 4 years ago

I can reproduce this using the gopenpgp library directly:

package main

import (
    "fmt"
    "os"
    "log"
    "github.com/ProtonMail/gopenpgp/helper"
)

func main() {
    // Generated using: passphrase2pgp --uid 'passforios <passforios@example.com>' --input <(echo passforios) --subkey --armor
    const pubkey = `-----BEGIN PGP PUBLIC KEY BLOCK-----

mDMEAAAAABYJKwYBBAHaRw8BAQdA/w7UpmqD3wnD69YSKpJ8E7Ml8a6poRgolIpL
NmDdtEm0I3Bhc3Nmb3Jpb3MgPHBhc3Nmb3Jpb3NAZXhhbXBsZS5jb20+iGQEExYI
ABYFAgAAAAAJEPEjCrixFCE5AhsDAh4BAAChzQEAl899IV1vzHNqFiFjZQWxq1a0
oi9BVGaLJac+ECBs/NQA/jciYLJQnsdg/tcPdHJ63J5ZLBE7acdee+eE6QWbuRAH
uDgEAAAAABIKKwYBBAGXVQEFAQEHQM+cXZ5W1y+N6w1z4B2RQgaDvXYAvvXxQhD9
15ExxAUpAwEICYhhBBgWCAATBQIAAAAACRDxIwq4sRQhOQIbDAAAOZsA/3jvGQDh
C62jPKfVXZk2JrHuFzUcpYj7woFNz/Z24eOlAQDL5I2rA1FSS62lgISDlMjrkwmX
6iM98rMDdbAAP0v5Bw==
=aiqQ
-----END PGP PUBLIC KEY BLOCK-----
`

    armor, err := helper.EncryptMessageArmored(pubkey, "plain text")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Fprintf(os.Stdout, armor)
}

gpg -d fails with:

gpg: encrypted with 256-bit ECDH key, ID 54F7F66E3272CA09, created 1970-01-01
      "passforios <passforios@example.com>"
gpg: public key decryption failed: Wrong secret key used
gpg: decryption failed: No secret key
Fastidious commented 1 year ago

What version of gpg are you using, @jakajancar?