January 04, 2015

GPG - Migration from SHA1 to SHA2

After the CRYPTO 2004 results were published, NIST announced that they planned to phase out the use of SHA-1 by 2010 in favor of the SHA-2 variants. In 2009 at eurocrypt, a small group of researchers announced a fairly serious attack against the SHA-1 digest algorithm

By default gpg uses CAST5 as a cipher and SHA1 as hash. Below are the steps required to migrate from SHA1 to SHA2 in GPG setup.

In this article I’ve also switched from CAST5 to AES256 cipher, however this is not necessary as there are no known attacks on CAST5-128.

To some users changing the cipher/hash might be inconvenient as the recipient’s version of their GPG might be incompatible with the other cipher/hash.

Some people prefer to generate new keys, however there is a way to keep your key and change just the cipher/hash. This is especially useful when you want to keep your key fingerprint the same and signatures made by your parties. I must also note that most likely your parties have signed your public key using SHA1 hash, so you can ask them to sign it again with a stronger hash.

IMPORTANT: Before you do anything, please make sure you backed-up your imporant keys!

Before we start

To make GPG keys generation remarkably faster, install “rng-tools” package Debian-based:

apt-get install rng-tools -y

RPM-based:

yum install rng-tools -y

The rngd daemon will establish a bridge between the hardware TRNG (True random number generator) and the kernel entropy pool.

To view your current settings over your keys

Secret key (the one you keep private and never share)

laptop ~ $ gpg -o Alice.sec --export-secret-keys Alice
laptop ~ $ gpg -vv --import Alice.sec

IMPORTANT: Do not forget to destroy/shred this temporary copy of your secret key.

Public key

laptop ~ $ gpg -o Alice.pub --export Alice
laptop ~ $ gpg -vv --import Alice.pub

When viewing your key, you should check your private key output for lines like:

iter+salt S2K, algo: 3, SHA1 protection, hash: 2, salt: c1838489ffcb8b8d

You can observe the algo (cipher) is 3 and the hash (digest) is 2.

Run the following command in order to determine what number corresponds to what cipher/hash:

laptop ~ $ gpg -vv --version
gpg (GnuPG) 1.4.16
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Home: ~/.gnupg
Supported algorithms:
Pubkey: RSA, RSA-E, RSA-S, ELG-E, DSA
Cipher: IDEA (S1), 3DES (S2), CAST5 (S3), BLOWFISH (S4), AES (S7),
        AES192 (S8), AES256 (S9), TWOFISH (S10), CAMELLIA128 (S11),
        CAMELLIA192 (S12), CAMELLIA256 (S13)
Hash: MD5 (H1), SHA1 (H2), RIPEMD160 (H3), SHA256 (H8), SHA384 (H9),
      SHA512 (H10), SHA224 (H11)
Compression: Uncompressed (Z0), ZIP (Z1), ZLIB (Z2), BZIP2 (Z3)

So the cipher is (S3) CAST5, and the hash is (H2) SHA1.

Updating your secret key

Say you want to use AES256/SHA512 as cipher/hash, so you want to run the following command

laptop ~ $ gpg -u Alice --s2k-digest-algo SHA512 --s2k-cipher-algo AES256 --edit-key Alice
gpg> passwd
gpg> save

This will prompt you to type your current password and the new one. After this is set, write “save” and confirm saving changes and quit.

In order to see if this was really set, you can export your secret key again and view it as described above.

You should see similar line as this:

iter+salt S2K, algo: 9, SHA1 protection, hash: 10, salt: c7c377b33e8546b5

Here you can see algo 9 stands for (S9) AES256 and hash 10 is for (H10) SHA512, just as we were expecting.

You can also use “pgpdump” command over your exported key in order to see more details as such:

...
	Sym alg - AES with 256-bit key(sym 9)
	Iterated and salted string-to-key(s2k 3):
		Hash alg - SHA512(hash 10)
		Salt - c7 c3 77 b3 3e 85 46 b5 
		Count - 65536(coded count 96)
...

Note that this modification does not change anything in your public key.

Updating your public key

Here we will update cipher/hash preferences of your public key, so that client software of the parties who wish to communicate with you, will prefer them in the order you (your public key) prefer.

NOTE: This is not always valid and can be overriden by the client software settings.

laptop ~ $ gpg -u Alice --edit-key Alice
gpg> showpref
[ultimate] (1). Alice <alice@wonderland>
     Cipher: AES256, AES192, AES, CAST5, 3DES
     Digest: SHA256, SHA1, SHA384, SHA512, SHA224
     Compression: ZLIB, BZIP2, ZIP, Uncompressed
     Features: MDC, Keyserver no-modify

gpg> setpref SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed

gpg> showpref
[ultimate] (1). Alice <alice@wonderland>
     Cipher: AES256, AES192, AES, CAST5, 3DES
     Digest: SHA512, SHA384, SHA256, SHA224, SHA1
     Compression: ZLIB, BZIP2, ZIP, Uncompressed
     Features: MDC, Keyserver no-modify

gpg> save

Checking the difference, you will see that only the preferred cipher/hash and compression algorithms changed in your public key (pref-sym-algos, pref-hash-algos, pref-zip-algos).

Note that this modification does not change anything in your secret key.

Post-action (signatures and hashes)

Once you have updated your secret & public key, you might still notice SHA1 is used as hash in your keys:

laptop ~ $ gpg -vv --import Alice.sec 2>&1 |grep digest
	digest algo 2, begin of digest a5 f0
	digest algo 2, begin of digest d2 de
laptop ~ $ gpg -vv --import Alice.pub 2>&1 |grep digest
	digest algo 2, begin of digest 66 f0
	digest algo 2, begin of digest d2 de

The reason of that is the self-signature. When you generated your keys (–gen-key), GPG asked for your Real name / Email .. which was used to create a user ID (UID). Then GPG automatically signed this record with your corresponding secret key. It used SHA1 hash, this is why you still see it in your pub/sec keys as shown above.

laptop ~ $ gpg -u Alice --edit-key Alice 
gpg> list

pub  4096R/A28E505A  created: 2015-01-04  expires: 2015-01-05  usage: SC  
                     trust: ultimate      validity: ultimate
sub  4096R/394AAE32  created: 2015-01-04  expires: 2015-01-05  usage: E   
[ultimate] (1). Alice <alice@wonderland>

gpg> check
uid  Alice <alice@wonderland>
sig!3        A28E505A 2015-01-04  [self-signature]

gpg> quit

To remedy this (SHA1 hash over your UID), you need to delete your UID and create it again (will be signed with SHA-2). But first update your GPG client preferences:

~/.gnupg/gpg.conf
personal-cipher-preferences AES256
personal-digest-preferences SHA512
cert-digest-algo SHA512
default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed

NOTE: Always keep s2k digest/cipher parameters when you need to create new keys as it involves steps like protecting your new secret keys (or secret subkeys) with your password using the digest(==hash)/cipher you specified.

IMPORTANT: Do not specify the same values when you create your new UID! Otherwise GPG will link your new UID (sha2) to your previous UID, and when you will remove your previous UID (sha1), it will keep no any user ID assigned to your secret key. Because of that GPG won’t display the “uid” when listing the secret keys (gpg -K). I think it can cause other undesirable effects.

I suggest to at least add something to the “Comments” section.

If you really want to keep the same values (Real name, Email, Comments), then you can create a 2nd UID with some different value, remove the 1st UID, and create the 3rd UID with the values you desire. After that you can remove the 2nd UID.

laptop ~ $ gpg -u Alice --s2k-digest-algo SHA512 --s2k-cipher-algo AES256 --edit-key Alice

gpg> toggle

sec  2048R/EA9C889E  created: 2015-01-04  expires: 2015-01-05
ssb  2048R/AD5A81B2  created: 2015-01-04  expires: never     
(1)  Alice <alice@wonderland>

gpg> toggle

pub  2048R/EA9C889E  created: 2015-01-04  expires: 2015-01-05  usage: SC  
                     trust: ultimate      validity: ultimate
sub  2048R/AD5A81B2  created: 2015-01-04  expires: 2015-01-05  usage: E   
[ultimate] (1). Alice <alice@wonderland>

Create a new temporary UID

gpg> adduid
Real name: Alice
Email address: alice@wonderland
Comment: temporary

Select original UID and delete it (to avoid the linking problem)

gpg> uid 1
gpg> deluid

Create a new UID with the same values as you had in your original UID

gpg> adduid
Real name: Alice
Email address: alice@wonderland
Comment: 

Select a temporary UID and delete it

gpg> uid 1
ggp> deluid

gpg> save

This way you will have Real name, Email and Comments unchanged, and the UID will be signed with SHA1 hash.

GPG also created the subkey (sub) and the secret subkey (ssb) which are used for encryption/decryption And the subkey was signed by your secret key, again with the SHA1 digest. You can either delete your subkey or revoke the signature of your subkey. The latter will stop the parties from using that subkey but will still let you decrypt the data which was encrypted in past with its corresponding secret subkey (ssb). If you don’t have anything that you still need to decrypt with your old subkey, you can remove it completely:

(Option A) To remove your sub/ssb keys:

gpg> key 1
gpg> delkey

(Option B) To revoke your sub/ssb keys:

gpg> key 1
gpg> revkey

After that you need to create new sub/ssb keypair:

gpg> addkey

Choose RSA or Elgamal and (encrypt only).

gpg> save

Now use methods above to export and view the properties of your keys to ensure that cipher/hash used as you set.

For obvious reasons, don’t forget to shred the secret key copy we did for tests

shred -uvz Alice.sec ; rm Alice.pub