I've written a script to help our developers store a copy of their private keys without a passphrase inside our Puppet tree (not committed to Git) so our Vagrant boxes can use Hiera with eyaml + gpg (https://github.com/sihil/hiera-eyaml-gpg) to access secret data during testing.

The script works great, but I'd like to also automate the process of verifying that the secret key has been stripped of a passphrase properly in the copy.

So far, the only way I found is manual - execute gpg --homedir ... --edit-key keyid and then in the interactive prompt run password and look for a This key is not protected. message.

I'd like to do that automatically in the script - basically I want to know how does the gpg tool know that it should print this message. From the answer in https://security.stackexchange.com/a/54205/45966 and reading the GnuPG source code in g10/export.c I conclude that "no passphrase" is actually regarded as "passphrase is empty string" and the code actually tries to decrypt a random string with the passphrase and verify that the result contains repeated random pattern.

Is this correct?

If so - is there a way to avoid having to re-implement that entire process myself but instead use gpg command line tool or some Python/Ruby API's to do that for me? I looked at a few Python and Ruby front-ends to gpgme but didn't see something like this there.

I see in g10/build-packet.c that I should expect some different output if the packet is protected or not, but trying to compare dumps of protected vs. unprotected secret keys didn't yield anything except small differences in hashes. I might be mis-interpreting the code there.

  • This is particularly useful if you want to follow the procedure in the GnuPG manual at gnupg.org/documentation/manuals/gnupg/… which allows one to generate a key either with no passphrase or with one written in a plain text file May 8, 2017 at 14:21

1 Answer 1


From my testings, gpg --list-packets will yield different results depending on whether the key is encrypted or not. A key generated without passphrase will directly have information on the key revealed:

:secret key packet:
    version 4, algo 1, created 1444376378, expires 0
    skey[0]: [1024 bits]
    skey[1]: [17 bits]
    skey[2]: [1017 bits]
    skey[3]: [512 bits]
    skey[4]: [512 bits]
    skey[5]: [510 bits]
    checksum: 9df4
    keyid: [snip]

while a key with passphrase only gives information on the public key parts and string-to-key procedures in use:

:secret key packet:
        version 4, algo 1, created 1378729401, expires 0
        skey[0]: [1024 bits]
        skey[1]: [17 bits]
        iter+salt S2K, algo: 3, SHA1 protection, hash: 10, salt: e182c39f07747f0c
        protect count: 65011712 (255)
        protect IV:  d5 0d 20 dc cb a2 e9 16
        encrypted stuff follows
        keyid: 99543578D453449B

You'd still have to parse the output, but this should be stable enough to directly go for absence of a [whatever] S2K line (there are different S2K procedures, so make sure to fetch them all or use some kind of wild card). Sadly, there is no special --with-colons output for --list-packets that would be easier and more reliable to parse.

  • (EDITED) Thanks Jens-Erat. I now think that I see the error of my previous experiment - I was using "--export" instead of "--export-secret-keys" to check the result. Now that I use "--export-secret-keys" I see these differences in my keys. Oct 9, 2015 at 8:12
  • 1
    --export only exports public keys -- that's why you will not see any information on the encryption of secret keys.
    – Jens Erat
    Oct 9, 2015 at 8:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.