Adding GPG Stored Keys

I’m trying to add GPG keys to the OnlyKey by adding ECC encryption and signing subkeys from my master keychain which is stored offline.

I’ve successfully added the encryption subkey (cv25519) which is loaded in slot ECC1 but when I try and add the signing subkey (ed25519) in ECC2 I get the error:

TypeError: Cannot read property 'data' of undefined

I see in another thread it says:

Is this related? Both key types are in the OpenPGP standard I believe. If I can’t get gpg keys loaded what are the options? Only having four RSA key slots means I can’t use RSA keys as I need more than four. I want to generate my own signing and encryption keys and load those. How is this done?

– BVS

It sounds like OpenPGP.js (which is used to load the keys in the desktop app) cannot parse your OpenPGP key. This is usually due to not being an OpenPGP compatible key. There is a way to load raw keys in the Advanced tab of the app.

Thanks @t11 but how do I do that? The raw ECC key needs to be 32-byte hex but gpg doesn’t output the raw key, only either ASCII armored text or binary. I’ve tried to convert the key as follows:

xxd -l 32 -p binary-private-key.asc

It’s expecting a 64 character value and that’s accepted but I’ll need to test if this is correct.

Help appreciated.

EDIT: -l only writes up to x length of the output so truncates it. If I remove it I get the full hex but it’s much more than 64 characters.

– BVS

I still haven’t manged to have any luck importing the ECC key. I started down this path wanting to use derived keys but discovered in this thread that you can’t export the key for backup, which means reliance on Onlykey which I’d like to avoid.

So for my particular use case, I’m looking at stored keys. As I said I can use RSA keys but I need more than four, so ECC seems to be the only way to go. Is there some documentation on how to import ECC keys created by GPG? As I understand it GPG ECC keys are compatible with the OpenPGP standard.

What else can I do to troubleshoot this? If I must use raw keys how do I convert an ASCII armored key to the required format?

– BVS

Currently only OpenPGP keys are supported for import. Create a key with a service like Keybase or Protonmail and it will work. GPG keys are not supported but may work - Import keys from Keybase, Protonmail, and Mailvelope/GPG | Docs

1 Like

Thanks @t11, that’s what I’m not understanding though; AFAIK GPG is just an implementation of the OpenPGP standard. So aren’t OpenPGP keys = GPG keys? I’m not sure what the libraries used by ProtonMail, Keybase, et al are doing differently.

I guess I’ll go off and take a look at OpenPGP.js and kbpgp and see if I can use those to create my own key. I’d like to generate my own key rather than rely on a third-party.

– BVS

Hi @t11,

Sorry to be a pain but you’ll have seen I’ve been trying to get my OpenPGP keys loaded on the OnlyKey; I can’t for the life in me get it to work! Currently I’m stuck, and have spent hours trying.

I originally tried to get X25519 ECC keys loaded using GPG but that doesn’t work and you explained GPG isn’t supported for stored keys but may work. I was getting ‘TypeError: Cannot read property ‘data’ of undefined’ which seems to confirm as much. In a last attempt to get X25519 keys working I tried using the kbpgp library so I could generate my own keys offline but the code I put together only created NIST256P1 keys, and I couldn’t figure out how to generate X25519 keys.

So I tried reverting back to RSA keys with a key size of 4096, and to ensure it was compatible I used this site for testing - pgpkeygen.com which should give Keybase.io compatible keys. When I auto load into the OnlyKey it seems to work with the message ‘Successfully set RSA key’. From the documentation I think these keys should be stored as:

  • RSA 1 - decryption key
  • RSA2 - signing key

So I believe I need to initialize the local keystore with:

onlykey-gpg init "Testy Test <test@test.com>" -sk 2 -dk 1 -i somekey-pub.asc -e rsa

But I get the error ‘gpg: error reading key: No secret key’.

I also tried using the exported key and loading manually into the correct slots but that doesn’t work either, I get the same error. I even tried using GPG, which also loads RSA keys fine onto the OnlyKey but I get the same error. Even exporting the subkeys with ‘–export-secret-subkeys’ and loading them into the slots doesn’t work either.

I’ve tried everything I can think of. Do you have any ideas? If I can’t get it to work I may have to use Keybase to generate and load the key but it’s not really what I want to do. The reason I bought the OnlyKey was for secure offline storage of PGP keys and passwords so I’ll be a little disappointed if I have to use a service to generate it. I wouldn’t mind if Keybase offered an offline keygen but you literally have to login just to do keygen even on the CLI, which seems dubious to me even if the client is FOSS.

Please help me out.

– BVS

OK, so to get back to basics I’ve tried loading a ProtonMail X25519 key using the autoload function as per the docs here. It says the ECC key loaded successfully. I can use WebCrypt to encrypt and sign a message so I’ve proved the key is loaded fine.

Now, as per the docs here I’m trying to use those stored keys with the GPG agent such as:

onlykey-gpg init “My User <myuser@pm.me>” -sk 102 -dk 101 -i publickey.myuser@pm.me.asc

As I understand it the ECC keys should be loaded into the first slots. The latest firmware doesn’t actually tell me the number of those slots however. Still I have the problem as before:

So to conclude, I’m either being a dunce or these keys don’t work with the local GPG agent. May be this is not the intended usage but the example does show a ProtonMail public key passed as an argument. I understand that Keybase and ProtonMail integration is via WebCrypt but was hoping to also use the keys locally to do other things.

– BVS

This should definitely work:

onlykey-gpg init “My User <myuser@pm.me>” -sk 102 -dk 101 -i publickey.myuser@pm.me.asc

I just tested this, here is what you should see:

$ rm -rf /Users/t/.gnupg/trezor && onlykey-gpg init “crptest@protonmail.com” -sk 102 -dk 101 -i publickey.crptest@protonmail.com.asc && echo “secret message” | gpg2 --encrypt -r “crptest@protonmail.com” | gpg2 --decrypt

2021-03-23 13:35:22,626 WARNING This GPG tool is still in EXPERIMENTAL mode, so please note that the API and features may change without backwards compatibility! [init.py:128]
2021-03-23 13:35:22,670 WARNING NOTE: in order to re-generate the exact same GPG key later, run this command with “–time=0” commandline flag (to set the timestamp of the GPG key manually). [init.py:41]
gpg: inserting ownertrust of 6
gpg: checking the trustdb
gpg: marginals needed: 3 completes needed: 1 trust model: pgp
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
sec ed25519 2021-02-15 [SC]
DE1F327B3F5F343A317880FEDF697F7407CFA758
uid [ultimate] crptest@protonmail.com crptest@protonmail.com
ssb cv25519 2021-02-15 [E]

gpg: encrypted with 256-bit ECDH key, ID 3AF7E439D40EE4FA, created 2021-02-15
crptest@protonmail.com crptest@protonmail.com
secret message

However, you must have “Stored Key User Input Mode” set to “Button Press Required” for GPG use as we don’t have a way for GPG to present the challenge code to a user:

If this is not set, you will get the error:

gpg: public key decryption failed: End of file
gpg: decryption failed: No secret key

I will work on testing and updating documentation to include key creation in GPG (instead of just Protonmail/Keybase support). Also for your other issue, RSA keys are only currently supported with SSH for GPG agent you must use an X25519 or nistp256 key.

@bettyvschmartz I have tested this with a key created from GPG and this works. Here is how to create key in GPG to use with OnlyKey agent:

$ gpg --expert --full-gen-key
gpg (GnuPG) 2.2.20; Copyright (C) 2020 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Please select what kind of key you want:
(1) RSA and RSA (default)
(2) DSA and Elgamal
(3) DSA (sign only)
(4) RSA (sign only)
(7) DSA (set your own capabilities)
(8) RSA (set your own capabilities)
(9) ECC and ECC
(10) ECC (sign only)
(11) ECC (set your own capabilities)
(13) Existing key
(14) Existing key from card
Your selection? 9
Please select which elliptic curve you want:
(1) Curve 25519
(3) NIST P-256
(4) NIST P-384
(5) NIST P-521
(6) Brainpool P-256
(7) Brainpool P-384
(8) Brainpool P-512
(9) secp256k1
Your selection? 1
Please specify how long the key should be valid.
0 = key does not expire
= key expires in n days
w = key expires in n weeks
m = key expires in n months
y = key expires in n years
Key is valid for? (0)
Key does not expire at all
Is this correct? (y/N) y

GnuPG needs to construct a user ID to identify your key.

Real name: Bob Smith
Email address: bob@protonmail.com
Comment:
You selected this USER-ID:
“Bob Smith bob@protonmail.com

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: /home/kali/.gnupg/trustdb.gpg: trustdb created
gpg: key FFADEA1DA23333FD marked as ultimately trusted
gpg: directory ‘/home/kali/.gnupg/openpgp-revocs.d’ created
gpg: revocation certificate stored as ‘/home/kali/.gnupg/openpgp-revocs.d/04C64623EA51A3B79658DBF7FFADEA1DA23333FD.rev’
public and secret key created and signed.

pub ed25519 2021-03-23 [SC]
04C64623EA51A3B79658DBF7FFADEA1DA23333FD
uid Bob Smith bob@protonmail.com
sub cv25519 2021-03-23 [E]

Then load the private key in the OnlyKey app the same way you would load a Protonmail key:

image

Make sure you have stored key mode set:

image

Then to use the GPG key with OnlyKey agent:

$ rm -rf /Users/t/.gnupg/trezor && onlykey-gpg init “bob@protonmail.com” -sk 102 -dk 101 -i /Users/t/Downloads/testpub.asc && echo “secret message” | gpg2 --encrypt -r “bob@protonmail.com” | gpg2 --decrypt
2021-03-23 16:59:56,737 WARNING This GPG tool is still in EXPERIMENTAL mode, so please note that the API and features may change without backwards compatibility! [init.py:128]
2021-03-23 16:59:56,768 WARNING NOTE: in order to re-generate the exact same GPG key later, run this command with “–time=0” commandline flag (to set the timestamp of the GPG key manually). [init.py:41]
gpg: inserting ownertrust of 6
gpg: checking the trustdb
gpg: marginals needed: 3 completes needed: 1 trust model: pgp
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
sec ed25519 2021-03-23 [SC]
04C64623EA51A3B79658DBF7FFADEA1DA23333FD
uid [ultimate] Bob Smith bob@protonmail.com
ssb cv25519 2021-03-23 [E]

gpg: encrypted with 256-bit ECDH key, ID 4B433249E7DE1630, created 2021-03-23
“Bob Smith bob@protonmail.com
secret message

Hi @t11, this still doesn’t work. The ECC keys seems to load fine such that they give a success message but I get the same error:

I’ve tried this on Tails afresh and on Ubuntu with the same problem. On Ubuntu the gpg version is 2.2.20 which is the same as the version you’re using.

If I try on WebCrypt by pasting the corresponding pub key, I can sign a message so I think I can confirm the private key has loaded, although I have no other way to check. When I try and wipe the ECC slots using the app I get no messages unlike when wiping RSA slots.

I can also interface with the OnlyKey using onlykey-cli so it’s unlocked and loaded.

– BVS

I am not able to replicate this issue. I can produce an error of " gpg: public key decryption failed: End of file gpg: decryption failed: No secret key" if Stored Key Input Mode is not set to Button Press Required.

I set up a new OnlyKey, used the method described above to generate key with GPG and load to OnlyKey. Here is the public and private test key:

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

mDMEYFo6+BYJKwYBBAHaRw8BAQdADsrier6zOgqrP5v8X1NlXuKRRDgBrnMmHWvm
ubq96sK0HkJvYiBTbWl0aCA8Ym9iQHByb3Rvbm1haWwuY29tPoiQBBMWCAA4FiEE
BMZGI+pRo7eWWNv3/63qHaIzM/0FAmBaOvgCGwMFCwkIBwIGFQoJCAsCBBYCAwEC
HgECF4AACgkQ/63qHaIzM/0YBAD+MbrMP+sdpXVqnenBVPfIi2/QK+BklLqazdA3
nma7BiIA/1x0THRtg7kfHnhLkIyxIgEU1SnA+7rqrKElw/j8s+oPuDgEYFo6+BIK
KwYBBAGXVQEFAQEHQBB6moBI34fneaxh5UmH9Oi3vt0ZI8dGxUu7V7ZKKNxNAwEI
B4h4BBgWCAAgFiEEBMZGI+pRo7eWWNv3/63qHaIzM/0FAmBaOvgCGwwACgkQ/63q
HaIzM/3RUAD7BXruGXYCfJverTPGs66dAPbtIQkGUgO2Dac7+8hdRrcBAKv8F5Yc
7byGWN6dbprtp2WwbPJboi2F++Ktf++akN4C
=R0qg
-----END PGP PUBLIC KEY BLOCK-----

-----BEGIN PGP PRIVATE KEY BLOCK-----

lIYEYFo6+BYJKwYBBAHaRw8BAQdADsrier6zOgqrP5v8X1NlXuKRRDgBrnMmHWvm
ubq96sL+BwMCaAERuYdGlt//KtY2WriQYdaEx2Tu/fTBKJ0IzlPll7cWaIBL+DDe
S/cRvSM4pILh3Zy6qU2/PMNWNC4eC529GLliTQl/43GC1Rqxlnyc67QeQm9iIFNt
aXRoIDxib2JAcHJvdG9ubWFpbC5jb20+iJAEExYIADgWIQQExkYj6lGjt5ZY2/f/
reodojMz/QUCYFo6+AIbAwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRD/reod
ojMz/RgEAP4xusw/6x2ldWqd6cFU98iLb9Ar4GSUuprN0DeeZrsGIgD/XHRMdG2D
uR8eeEuQjLEiARTVKcD7uuqsoSXD+Pyz6g+ciwRgWjr4EgorBgEEAZdVAQUBAQdA
EHqagEjfh+d5rGHlSYf06Le+3Rkjx0bFS7tXtkoo3E0DAQgH/gcDAstHyWwUx5KN
/+HnCurMC5mnhWYEkQXH6RTalNvGy0kGKiGYnVdY4Qbs3rO+d9AcOhBl+6x7Pkpd
WDgrkFYJ41rNFVRG+obgEsnR/99XPMmIeAQYFggAIBYhBATGRiPqUaO3lljb9/+t
6h2iMzP9BQJgWjr4AhsMAAoJEP+t6h2iMzP90VAA+wV67hl2Anyb3q0zxrOunQD2
7SEJBlIDtg2nO/vIXUa3AQCr/BeWHO28hljenW6a7adlsGzyW6IthfvirX/vmpDe
Ag==
=Snwn
-----END PGP PRIVATE KEY BLOCK-----

passphrase bob

I load this key through the OnlyKey app like this:

After key is loaded I run this command:

$ rm -rf /Users/t/.gnupg/trezor && onlykey-gpg init “bob@protonmail.com” -sk 102 -dk 101 -i testpub.asc && echo “secret message” | gpg2 --encrypt -r “bob@protonmail.com” | gpg2 --decrypt

sec ed25519 2021-03-23 [SC]
04C64623EA51A3B79658DBF7FFADEA1DA23333FD
uid [ultimate] Bob Smith bob@protonmail.com
ssb cv25519 2021-03-23 [E]

gpg: encrypted with 256-bit ECDH key, ID 4B433249E7DE1630, created 2021-03-23
“Bob Smith bob@protonmail.com
secret message

@t11 I don’t know what else to tell you. For the latest test I literally copied and pasted the commands you posted right up to also using “bob@protonmail.com”. I have been into the OnlyKey app and set Stored Key Input Mode to Button Press Required about 5 times (of which I already had that set anyway) and I still get the same error.

So… to confirm:

  1. I put the device in config mode (hold 6 and key flashes red)
  2. I paste the ECC private key which shows successful
  3. I go and set “Set Stored User Input Mode” (which should say “Set Stored User Key Input Mode” btw) to “Button Press Required” which also shows successfully set
  4. Pull the key and try on my test device along with copying over the pub key, and get the error

It still doesn’t work. I also tried setting back to “Challenge Code Required” and reset back to “Button Press Required” too. I don’t know what else I can do to debug the issue further. I even loaded it onto another OnlyKey which is an exact backup on my main key, with the same problem. I suspect the issue may be related to you using a brand new, previously unused OnlyKey.

– BVS

@t11 do you have any other debug options to try?

To rule out anything being borked on my OnlyKey I have taken a new OnlyKey and proceeded as follows.

Derived Key Mode

Firstly I set the key up using derived key mode and ran onlykey-gpg init "Bob Smith <bob@protonmail.com>" which completed fine and everything worked as it should. I did this to confirm the prerequisties were installed correctly. This confirms that the correct packages are installed and the udev rules are working.

Stored Key Mode - ProtonMail Key

I then switched to stored key mode, downloaded a ProtonMail ECC key pair and loaded it onto the OnlyKey which loaded fine. I tested this using Webcrypt and I can single-press to confirm, and encypt and sign a message.

I then reverted to GPG and tried the above command:

Which gave me the error as before that the key could not be read:

rm -rf ~/.gnupg/onlykey && onlykey-gpg init “bob@protonmail.com” -sk 102 -dk 101 -i bob-pub.asc && echo “secret message” | gpg --encrypt -r “bob@protonmail.com” | gpg --decrypt
2021-04-27 16:53:28,513 WARNING      This GPG tool is still in EXPERIMENTAL mode, so please note that the API and features may change without backwards compatibility! [__init__.py:128]
2021-04-27 16:53:28,531 WARNING      NOTE: in order to re-generate the exact same GPG key later, run this command with "--time=0" commandline flag (to set the timestamp of the GPG key manually). [__init__.py:41]
gpg: inserting ownertrust of 6
gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: error reading key: No secret key
Traceback (most recent call last):
    File "/home/amnesia/.local/bin/onlykey-gpg", line 33, in <module>
        sys.exit(load_entry_point('onlykey-agent==1.1.10', 'console_scripts', 'onlykey-gpg')())
    File "/home/amnesia/.local/bin/onlykey_agent.py", line 6, in <lambda>
        gpg_tool = lambda: libagent.gpg.main(DeviceType)
    File "/home/amnesia/.local/lib/python3.7/site-packages/libagent/gpg/__init__.py", line 375, in main
        return args.func(device_type=device_type, args=args)
    File "/home/amnesia/.local/lib/python3.7/site-packages/libagent/gpg/__init__.py", line 224, in run_init
        '--list-secret-keys', args.user_id]))
    File "/home/amnesia/.local/lib/python3.7/site-packages/libagent/gpg/__init__.py", line 114, in check_call
        subprocess.check_call(args=args, stdin=stdin, env=env)
    File "/usr/lib/python3.7/subprocess.py", line 347, in check_call
        raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['/usr/bin/gpg', '--homedir', '/home/amnesia/.gnupg/onlykey', '--list-secret-keys', '“bob@protonmail.com”']' returned non-zero exit status 2.

Stored Key Mode - GPG

For completeness, I then tried generating and loading an ECC key from GPG following the above steps you posted (which I have been doing all along). This again loaded fine and I tested it via Webcrypt. I added the pub key, recipient ProtonMail address, and message and I could encypt and sign a message fine.

Finally, I tried using GPG and I get the same error that the key could not be read!

I have the latest firmware loaded (v2.1.0-prodc) and the latest OnlyKey app (v5.3.1). I’m also using the same version of GPG.

I’m not sure why you can’t reproduce this but there is something wrong. I lost so much time on this. Maybe the hardware is faulty or something else but this should be simple enough. I don’t know what else can be the problem if it’s not a bug.

Is it best to get replacement devices to try or do you have something else to suggest?

– BVS

If you created your own Protonmail ECC key this would not be the correct command:

$ rm -rf /Users/t/.gnupg/trezor && onlykey-gpg init “bob@protonmail.com” -sk 102 -dk 101 -i /Users/t/Downloads/testpub.asc && echo “secret message” | gpg2 --encrypt -r “bob@protonmail.com” | gpg2 --decrypt

As you should replace bob@protonmail.com with yourusername@protonmail.com. Bob was just for the example above where I created a key with GPG where the user was set to bob@protonmail.com.

@t11 Yes, obviously, this is what I’ve done. It’s just an example to show you the error message. I didn’t want to post my email address for privacy reasons.

Could you please take a look at the rest?

– BVS

You’ll see that @George had the exact same problem here with stored keys Shared Key between GnuPG and WebCrypt

I don’t get the WebCrypt issue he mentions in the thread but you confirm you made some changes to WebCrypt that fixed that problem so that’s most likely why. He confirms the same issue all the way through the thread:

And that the same problem exists for both ProtonMail loaded key and GPG loaded keys. The error is thrown gpg: error reading key: No secret key.

Goes on to say:

Using generated keys works which is what I have confirmed. In Stored Key Mode it looks like it’s not connecting to the OnlyKey before trying to list the PK, which makes complete sense as to why there is no secret key error.

The conclusion here was that it’s not reproducible and that maybe it’s because he’s using QubesOS:

Yet it seems he confirmed it on Debian and Fedora as per his reply earlier (which I’ve re-quoted above), and I’ve also confirmed it on Ubuntu.

Also for completeness:

I’ve used a Trezor on QubesOS and can confirm that works fine as long as you pass through to the USB VM correctly, for the record. He’s also confirmed generated keys worked on QubesOS so you’d expect Stored Keys would too.

In conclusion, I think this is a bug. Looks like the keys are loaded fine which I’ve confirmed using WebCrypt. It seems the problem lies in not being able to read the PK properly. I see in your examples you’re using the Trezor build rather than the OnlyKey one - maybe this is the problem?

– BVS

It does seem like the same issue. To clarify: The fedora and debian VMs were also on Qubes. I don’t have another machine available for testing at the moment.

It could be a Qubes specific problem, but as generated keys function correctly this isn’t expected behaviour. Are you also running Qubes @bettyvschmartz?

No, I’m on Ubuntu so I think we’ve confirmed it’s not Qubes specific.

– BVS

@t11 @George taken this a little further. I know this thread has taken a few avenues - trying GPG generated keys and trying PM keys but I’ve been testing now solely with PM keys which I can always get working with WebCrypt.

Since trying PM keys, I used your command example @t11 to copy/paste (with relevant changes) to make sure I was definitely inline with what you were doing:

But I’ve since noticed that your speech marks are funky (“ vs ") which is the cause of the error gpg: error reading key: No secret key. Looks like Discourse is modifying them in blockquotes. I can now confirm that I’m confident this is the same issue @George reported.

So we’re comparing apples with apples, I’ve also reproduced this on Kali. Loaded the live CD and ran:

Then I ran:

rm -rf ~/.gnupg/onlykey && onlykey-gpg init “my-user@pm.me” -sk 102 -dk 101 -i publickey.my-user@pm.me.asc && echo “secret message” | gpg2 --encrypt -r “my-user@pm.me” | gpg2 --decrypt

Less the strange quotes symbols (replaced with normal ones) and where ‘my user’ is replaced with my username which I can confirm matches what’s shown in GPG when importing the pub key. The output is the error:

gpg: keydb_search failed: End of file
gpg: error reading key: End of file

We also know Stored Key Input Mode is set to Button Press Required. This error is irrelevant as to whether the OnlyKey is plugged in or not.

I’m able to reproduce this across Kali, Ubuntu and Tails.

@t11 have you been able to test this since? Are you using the same build?

– BVS