Reasonable Defaults for s2k
You can tune multiple parameters. The s2k-mode
should generally stay on it's default value, 3: this uses both a salt and repeats salt and passphrase during application of the digest function. Further parameters are the symmetric encryption algorithm (s2k-cipher-algo
), the digest algorithm (s2k-digest-algo
) and (if mode 3 is used) the number of repetitions of hash and passphrase, increasing the amount of data to be hashed (s2k-count
). All of those options can either be set in the GnuPG configuration file ~/.gnupg/gpg.conf
or on the command line (prefixed with --
, for example --s2k-digest-algo
).
For the three "tunable" options, you have to balance execution time and security.
s2k-cipher-algo
: As the amount of data to encrypt is very small, it does not really matter how much overhead is spent on encryption without a notable difference. The default AES128
should probably be fine, but why not use the additional security margin if we won't suffer from a notably higher computation effort?
s2k-digest-algo
and s2k-count
have impact on the time spent on hashing while trying to crack the passphrase. The default SHA-1 has some known weaknesses and is considered outdated, so choose some algorithm of the SHA-2 suite. While writing this answer, 65011712 repetitions and SHA512 resulted in each decryption operation taking a notable delay but far below a second on my mobile Core i7; if the decrypted key is cached in gpg-agent
anyway probably something one could live with.
I'm not aware of a discussion of reasonable defaults here, usually the recommendation is to make hashing as expensive as you can accept.
I don't care about slow arm processors. I would rather wait 100 milliseconds longer, and have my passphrase iterated 65011712 times.
If you really don't mind, the "heavy-duty" configuration will be
s2k-mode 3 # default anyway
s2k-cipher-algo AES256
s2k-digest-algo SHA512
s2k-count 65011712
For a still-totally-fine, but faster configuration reduce the computation effort for hashing by using a smaller value for s2k-count
or SHA256
. AES128 as cypher is fine, but does not result in a notable faster computation.
Using those Defaults for Private Key Encryption
TL;DR: You need to trigger saving the key again (for example by changing the passphrase), as exporting just dumps from hard disk. GnuPG 2.1 (modern) is affected by a bug.
The longer version:
You have to discriminate between several uses of digest algorithms in OpenPGP/GnuPG.
OpenPGP Fingerprints
For calculating fingerprints, OpenPGP requires keys to be hashed using SHA1, as you can read up in RFC 4880, Section 12.2, Key IDs and Fingerprints:
A V4 fingerprint is the 160-bit SHA-1 hash of the octet 0x99,
followed by the two-octet packet length, followed by the entire
Public-Key packet starting with the version field.
There is no choice or possibility to configure this. We will observe this again further down.
Modification Detection Code Packet
The Modification Detection Code Packet also uses an SHA-1 hash to protect encrypted messages from being manipulated, no choice is left for configuration. This is not really relevant for the further discussion, I just mentioned it for completeness.
Symmetrically Encrypted Session Key and Data Packages
These package are used both in "normal" OpenPGP messages encrypted for a public key, where they again contain the literal data package and for messages encrypted with a passphrase.
In the first case, the symmetric key is encrypted using an asymmetric algorithm like RSA, no passphrase (or hashing of such one) is involved.
It can also be used to encrypt a message symmetrically based on a passphrase, for example using gpg --symmetric
, which will ask for a passphrase and encrypt from STDIN. The pgpdump
(a tool similar to `gpg --list-packets, but sometimes providing more suitable output) output of such a message looks like
$ echo "foo" | gpg --passphrase "bar" --symmetric | pgpdump
Old: Symmetric-Key Encrypted Session Key Packet(tag 3)(13 bytes)
New version(4)
Sym alg - CAST5(sym 3)
Iterated and salted string-to-key(s2k 3):
Hash alg - SHA1(hash 2)
Salt - 1d cd 72 c8 c3 30 df 84
Count - 65536(coded count 96)
New: Symmetrically Encrypted Data Packet(tag 9)(26 bytes)
Encrypted data [sym alg is specified in sym-key encrypted session key]
Observe the settings for the string-to-key
procedure: the digest algorithm (SHA1 as default), and the mangle count. These can be configured using --s2k-digest-algo
and --s2k-count
. Lets see what happens if we set those to SHA512 and the maximum of 65011712:
$ echo "foo" | gpg --passphrase "bar" --s2k-digest-algo SHA512 --s2k-count 65011712 --symmetric | pgpdump
Old: Symmetric-Key Encrypted Session Key Packet(tag 3)(13 bytes)
New version(4)
Sym alg - CAST5(sym 3)
Iterated and salted string-to-key(s2k 3):
Hash alg - SHA512(hash 10)
Salt - ea 62 a1 ff 0b 2b f6 6a
Count - 65011712(coded count 255)
New: Symmetrically Encrypted Data Packet(tag 9)(26 bytes)
Encrypted data [sym alg is specified in sym-key encrypted session key]
We successfully changed the passphrase mangling options using the --s2k-...
options.
Passphrase Protected Exported Secret Keys
Now, let's get to one more use of the string-to-key
procedure, encrypting exported secret keys. RFC 4880, 5.5.3. Secret-Key Packet Formats indicates the same string-to-key
procedure should be in use, but indeed, --s2k-digest-option
and --s2k-count
have no effect any more:
$ gpg --s2k-digest-algo SHA512 --s2k-count 65011712 --export-secret-subkeys 0xDEADBEEF | pgpdump
[snip]
Old: Secret Subkey Packet(tag 7)(510 bytes)
Ver 4 - new
Public key creation time - Mon Jun 1 16:06:06 CEST 2015
Pub alg - RSA Encrypt or Sign(pub 1)
RSA n(1024 bits) - ...
RSA e(17 bits) - ...
Sym alg - CAST5(sym 3)
Iterated and salted string-to-key(s2k 3):
Hash alg - SHA1(hash 2)
Salt - ab 7d c8 36 6a 67 4d dd
Count - 65536(coded count 96)
IV - e9 76 d3 c4 b0 de 24 3c
Encrypted RSA d
Encrypted RSA p
Encrypted RSA q
Encrypted RSA u
Encrypted SHA1 hash
[snip]
This actually puzzled me for quite a while.
The solution was rather easy, though: gpg --export
simply exports the key from the secring.gpg
as-is. Setting the option for gpg --edit-key
(through parameters or the gpg.conf
file) and subsequently changing the passphrase using passwd
triggers writing the encrypted key to the secring.gpg
again -- and voilà, the key is encrypted as we wanted it to be, we don't even have to set the --s2k-...
options during export any more:
$ gpg --export-secret-subkeys 0xDEADBEEF | pgpdump
[snip]
Old: Secret Subkey Packet(tag 7)(510 bytes)
Ver 4 - new
Public key creation time - Mon Jun 1 16:06:06 CEST 2015
Pub alg - RSA Encrypt or Sign(pub 1)
RSA n(1024 bits) - ...
RSA e(17 bits) - ...
Sym alg - CAST5(sym 3)
Iterated and salted string-to-key(s2k 3):
Hash alg - SHA512(hash 10)
Salt - e1 82 c3 9f 07 74 7f 0c
Count - 65011712(coded count 255)
IV - 97 20 69 ae 8d ec 0d 3c
Encrypted RSA d
Encrypted RSA p
Encrypted RSA q
Encrypted RSA u
Encrypted SHA1 hash
[snip]
GnuPG 2.1 (modern)
As of 2015-06-01, GnuPG 2.1 ("modern" branch) is affected from a bug (GnuPG Issue #1800): here, the gpg-agent
takes care of all those operations, but does not care about the --s2k-...
options at all. This should be resolved soon, as the bug was already marked as urgent by Werner Koch, GnuPG's main developer.