How to generate gpg key without user interaction?
Solution 1:
It is likely that you are running out of entropy. Key generation requires a lot of very high-quality random numbers; without the activity of the user to provide high-quality randomness to the computer, the entropy pool is being exhausted by generation, and the generation process just hangs, waiting for the pool to refill.
Your choices, in order of increasing satisfactoriness, are
reconfiguring gpg to use the non-blocking pseudorandom number generator, which would be most unwise (though see below),
using a software solution to derive more entropy from existing system state (the kernel is notoriously conservative about how much entropy it is prepared to derive from system state, particularly where that state has no direct human input, eg CPU or NIC timings); as you have pointed out, haveged is one such solution, or
providing the computer with another physical source of high-grade entropy. Devices like the Entropy Key or the OneRNG can satisfy this requirement (I have no connection with either product save that I own an Entropy Key, and am very happy with it).
Edit: mzhaase draws my attention in a comment to this article on /dev/urandom vs. /dev/random (for which many thanks, it is an excellent article!) and takes issue with my dislike of using urandom
to create keys. In fact, the article does not say that the two sources are equivalent, and notes that
Linux's /dev/urandom happily gives you not-so-random numbers before the kernel even had the chance to gather entropy. When is that? At system start, booting the computer.
That is to say that, after boot, until the urandom
PRNG has been initialised with sufficient entropy, it really is unsafe to use it for key generation. That may take a while, especially on an unattended, headless server, and we don't know when the threshold has been reached, because the system doesn't explicitly tell us.
Now, if /dev/random
is prepared to issue numbers I may reasonably infer that the entropy pool is deep enough that urandom
will have been properly initialised. But if I have to check /dev/random
for blocking before each use of urandom
(which given that I generate keys less often than I reboot, is likely to be the case) I might as well just use the numbers from /dev/random
to generate my keys.
Solution 2:
I found there are a few simple changes that make your script work. I have also included a few tests so that once the key is created it will automatically be tested.
I also removed the password so that the key tests can be automated.
#!/usr/bin/env bash
rm -rf .gnupg
mkdir -m 0700 .gnupg
touch .gnupg/gpg.conf
chmod 600 .gnupg/gpg.conf
tail -n +4 /usr/share/gnupg2/gpg-conf.skel > .gnupg/gpg.conf
cd .gnupg
# I removed this line since these are created if a list key is done.
# touch .gnupg/{pub,sec}ring.gpg
gpg2 --list-keys
cat >keydetails <<EOF
%echo Generating a basic OpenPGP key
Key-Type: RSA
Key-Length: 2048
Subkey-Type: RSA
Subkey-Length: 2048
Name-Real: User 1
Name-Comment: User 1
Name-Email: [email protected]
Expire-Date: 0
%no-ask-passphrase
%no-protection
%pubring pubring.kbx
%secring trustdb.gpg
# Do a commit here, so that we can later print "done" :-)
%commit
%echo done
EOF
gpg2 --verbose --batch --gen-key keydetails
# Set trust to 5 for the key so we can encrypt without prompt.
echo -e "5\ny\n" | gpg2 --command-fd 0 --expert --edit-key [email protected] trust;
# Test that the key was created and the permission the trust was set.
gpg2 --list-keys
# Test the key can encrypt and decrypt.
gpg2 -e -a -r [email protected] keydetails
# Delete the options and decrypt the original to stdout.
rm keydetails
gpg2 -d keydetails.asc
rm keydetails.asc