Hi Ralf, On 25/10/17 23:29, Ralf wrote: > I was hoping for something simple and I think eventually this should be > simple; nevertheless I would make use of such a workaround / would be > thankful for such an example :)
I fiddled around with a test card. Prepare for a wall of text. I created a test key on card: --8<---------------cut here---------------start------------->8--- sec rsa2048/A7C45205828E4D09 created: 2017-10-31 expires: 2017-11-07 usage: SC card-no: 0005 0000106E trust: never validity: ultimate ssb rsa2048/D614DCD256D4028C created: 2017-10-31 expires: 2017-11-07 usage: A card-no: 0005 0000106E ssb rsa2048/93104C8F5B4A4714 created: 2017-10-31 expires: 2017-11-07 usage: E card-no: 0005 0000106E --8<---------------cut here---------------end--------------->8--- We start with damage control. Always backup your .gnupg directory before doing risky stuff. I'm assuming the backup dir .gnupg~ does not already exist; otherwise, delete it first or choose a different name. --8<---------------cut here---------------start------------->8--- $ cd $ cp -a .gnupg/ .gnupg~ --8<---------------cut here---------------end--------------->8--- The following actions: export secret key, delete secret key from keyring, import secret key, show an interesting behaviour of my GnuPG 2.1.18 related to card keys: --8<---------------cut here---------------start------------->8--- $ gpg -o cardkey.gpg --export-secret-keys 0976A143384202C99E7C26EFA7C45205828E4D09 $ gpg --delete-secret-and-public-keys-keys 0976A143384202C99E7C26EFA7C45205828E4D09 [...] $ gpg --import cardkey.gpg gpg: key A7C45205828E4D09: "Test Backup Hack" not changed gpg: To migrate 'secring.gpg', with each smartcard, run: gpg --card-status gpg: key A7C45205828E4D09: secret key imported gpg: Total number processed: 1 gpg: unchanged: 1 gpg: secret keys read: 1 --8<---------------cut here---------------end--------------->8--- It will not import the secret key stubs[1]. What it is obliquely saying is: don't import key stubs, just insert your smartcard and run --card- status. Keep this in mind. It will come back in a different form. Don't run --card-status at this time, by the way. Now we start with packet surgery. Unlike a surgeon, we start by fully taking apart the body ;-). --8<---------------cut here---------------start------------->8--- $ cd tmp/ $ gpgsplit ../cardkey.gpg $ ls 000001-005.secret_key 000004-007.secret_subkey 000007-002.sig 000002-013.user_id 000005-002.sig 000003-002.sig 000006-007.secret_subkey --8<---------------cut here---------------end--------------->8--- I always have a "tmp" dir handy for throwaway stuff. Create an empty dir first if necessary. An OpenPGP file always consists of a stream of packets. gpgslit just splits these packets over multiple files without changing anything else. We need to figure out which of the "secret_subkey" files is the secret key stub for the encryption key. First note that the encryption key is the key with ID 93104C8F5B4A4714, as can be told from the off-card backup file named sk_93104C8F5B4A4714.gpg. --8<---------------cut here---------------start------------->8--- $ cat *secret*|gpg --list-packets # off=0 ctb=95 tag=5 hlen=3 plen=294 :secret key packet: version 4, algo 1, created 1509451630, expires 0 pkey[0]: [2048 bits] pkey[1]: [17 bits] gnu-divert-to-card S2K, algo: 0, simple checksum, hash: 0 serial-number: d2 76 00 01 24 01 02 00 00 05 00 00 10 6e 00 00 keyid: A7C45205828E4D09 # off=297 ctb=9d tag=7 hlen=3 plen=294 :secret sub key packet: version 4, algo 1, created 1509451630, expires 0 pkey[0]: [2048 bits] pkey[1]: [17 bits] gnu-divert-to-card S2K, algo: 0, simple checksum, hash: 0 serial-number: d2 76 00 01 24 01 02 00 00 05 00 00 10 6e 00 00 keyid: D614DCD256D4028C # off=594 ctb=9d tag=7 hlen=3 plen=294 :secret sub key packet: version 4, algo 1, created 1509451630, expires 0 pkey[0]: [2048 bits] pkey[1]: [17 bits] gnu-divert-to-card S2K, algo: 0, simple checksum, hash: 0 serial-number: d2 76 00 01 24 01 02 00 00 05 00 00 10 6e 00 00 keyid: 93104C8F5B4A4714 --8<---------------cut here---------------end--------------->8--- These are the three packets with "secret" in their name, *in order*. The last of the three has the right key ID, so that means 000006-007.secret_subkey contains the stub we want to replace. Now let's take a look at that pesky sk_93104C8F5B4A4714.gpg that you were trying to import, with the off-card backup of the encryption key: --8<---------------cut here---------------start------------->8--- $ gpg --list-packets ~/.gnupg/sk_93104C8F5B4A4714.gpg # off=0 ctb=95 tag=5 hlen=3 plen=966 :secret key packet: version 4, algo 1, created 1509451630, expires 0 pkey[0]: [2048 bits] pkey[1]: [17 bits] iter+salt S2K, algo: 7, SHA1 protection, hash: 2, salt: 0B784F565A0849EB protect count: 28311552 (235) protect IV: 84 f1 35 77 5c f1 e2 70 b7 00 76 aa ef 85 86 6e skey[2]: [v4 protected] keyid: 93104C8F5B4A4714 --8<---------------cut here---------------end--------------->8--- This is a "secret key packet", but we want a "secret sub key packet" (sic). Let's first copy this "secret key packet" in the correct place, and then grab your scalpel: --8<---------------cut here---------------start------------->8--- $ cp ../.gnupg/sk_93104C8F5B4A4714.gpg 000006-007.secret_subkey $ dd if=000006-007.secret_subkey bs=1 count=1|hd 1+0 records in 1+0 records out 00000000 95 |.| 00000001 1 byte copied, 3.1911e-05 s, 31.3 kB/s $ echo -ne '\x9d' | dd of=000006-007.secret_subkey bs=1 conv=notrunc 1+0 records in 1+0 records out 1 byte copied, 3.4443e-05 s, 29.0 kB/s --8<---------------cut here---------------end--------------->8--- With the first "dd", we check if the file starts with the byte 0x95. If so, we should replace that byte by 0x9d. If it doesn't start with 0x95, we need to grab a copy of RFC 4880 and figure out what to do next, but I have no reason to believe GnuPG will have used something else than 0x95 when it created your backup. It's just a safety check to be sure. Flipping that single bit in the first byte is what changes the packet from a "secret key packet" to a "secret sub key packet". So now we can reconstruct an OpenPGP file containing your private key, for just the encryption subkey. The other two keys (primary and authentication sub) are still key stubs pointing to the smartcard. --8<---------------cut here---------------start------------->8--- $ cat * >/../uncarded-key.gpg $ cd .. $ gpg --import uncarded-key.gpg gpg: key A7C45205828E4D09: "Test Backup Hack" not changed gpg: To migrate 'secring.gpg', with each smartcard, run: gpg --card-status gpg: key A7C45205828E4D09: secret key imported gpg: Total number processed: 1 gpg: unchanged: 1 gpg: secret keys read: 1 gpg: secret keys imported: 1 --8<---------------cut here---------------end--------------->8--- Ah, here is our friend "run gpg --card-status" from before. It wasn't phrased very nicely the first time around, but this time it's even more confounding. Of the one key processed, one key is unchanged. Of the same one key, one is imported. Uhuh. What has happened is that it has not imported the primary key and the authentication subkey. But it *has* imported the encryption subkey. So it has both not changed and imported one key. In a universe with a different logic, this makes perfect sense. Note the double meaning of "secret key": we use it both to refer to individual keys like the primary and each subkey, as well as to refer to the whole of a primary key with its subkeys. It's what makes this even more confounding. But, nonetheless, it works. We cannot use the primary or the auth key, at least until we insert the smartcard and run "gpg --card-status", but we *can* use the encryption subkey. It is now an on-disk key. --8<---------------cut here---------------start------------->8--- $ echo test | gpg -r 0976A143384202C99E7C26EFA7C45205828E4D09 -o test.gpg -e gpg: test backup hack: Verified 0 signatures and encrypted 0 messages. File 'test.gpg' exists. Overwrite? (y/N) y $ gpg -d test.gpg gpg: encrypted with 2048-bit RSA key, ID 93104C8F5B4A4714, created 2017-10-31 "Test Backup Hack" test --8<---------------cut here---------------end--------------->8--- Workaround difficult enough for ya? :-) If you screw up your installation, you should be able to put it back by deleting ~/.gnupg and copying back ~/.gnupg~ in its place. I haven't encountered any issues with gpg-agent staying alive throughout this swapping of the floor under its feet. Either it is watching the inode number of its homedir or something like that and notices it changed, or I simply haven't managed to trip it up yet. It might be prudent to kill the agent in between. HTH, Peter. [1] "Secret key stub": a small bit of data that indicates on which smartcard the key is, rather than the actual secret key itself that would normally be there. -- I use the GNU Privacy Guard (GnuPG) in combination with Enigmail. You can send me encrypted mail if you want some privacy. My key is available at <http://digitalbrains.com/2012/openpgp-key-peter>
signature.asc
Description: OpenPGP digital signature
_______________________________________________ Gnupg-users mailing list Gnupg-users@gnupg.org http://lists.gnupg.org/mailman/listinfo/gnupg-users