Although i hardened all s2k options, they are silently ignored by doing a downgrade to old RFC4880-specs from 2007, when doing a private-key export. So the private key is only secured by AES-128 and SHA-1.
In 2015 you promised to fix this issue: https://dev.gnupg.org/T1800#84713
... but now under the "de-vs" mode aka "VS-NfD Modus", authorized for "VS-NfD" usage by the "BSI-VSA-10573" and "BSI-VSA-10584", this becomes an important security issue, when exporting private keys.
Here's a replay under "Gpg4Win 3.1.16" with "VS-NfD"-enforcement under "Windows 10":
In the log, you will see the enforced option "--openpgp" on export, that silently disables all "s2k"-hardenings and activates old RFC4880 conformity:
https://datatracker.ietf.org/doc/html/rfc4880#section-12.2
https://datatracker.ietf.org/doc/html/rfc4880#section-9.2
"... Implementations SHOULD implement AES-128 ..."
https://datatracker.ietf.org/doc/html/rfc4880#section-9.4
"... Implementations MUST implement SHA-1 ..."
For details see DEBUG-log of gpg-agent and gpg below:
Look for strings => !!!!!!! LOOK HERE !!!!!!!
To reproduce:
Run GnuPG (i.e. 2.2.28) in a client console on Windows 10 and create a private key with some hardenings for symmetric key encryption:
"gpg --s2k-cipher-algo AES256 --s2k-digest-algo SHA512 --s2k-mode 3 --s2k-count 65000000 --gen-key"
Do killall all kleopatra, gpg, gpg-agent, dirmngr processes ...
Use Open another admin console on Windows 10 and run gpg-agent in debug-mode:
"gpg-agent -v --debug-level expert --daemon"
Then use previously client console above on Windows 10 and run private key export of the previously generated key above, while monitoring the output on admin-console of gpg-agent:
"gpg --s2k-cipher-algo AES256 --s2k-digest-algo SHA512 --s2k-mode 3 --s2k-count 65000000 --export-secret-keys | gpg --list-packets" ... you will notice an export command like: "EXPORT_KEY --openpgp --cache-nonce= ..." <=== Downgrade to RFC4880 (although hardened in config / commandline) !!
Here you will see, that the output-crypto was downgraded to standard old "rfc4880-defaults" ...
- Details (gpg-agent output RSA PRIVATE-KEY Export request): ##############
C:\temp> gpg-agent -v --debug-level expert --daemon
gpg-agent[1116]: enabled debug flags: cache ipc
gpg-agent[1116]: Es wird auf Socket `C:\Users\xxxxxxxxxxx\AppData\Roaming\GnuPG\S.gpg-agent' gehört
gpg-agent[1116]: Es wird auf Socket `C:\Users\xxxxxxxxxxx\AppData\Roaming\GnuPG\S.gpg-agent.extra' gehört
gpg-agent[1116]: Es wird auf Socket `C:\Users\xxxxxxxxxxx\AppData\Roaming\GnuPG\S.gpg-agent.browser' gehört
gpg-agent[1116]: Es wird auf Socket `C:\Users\xxxxxxxxxxx\AppData\Roaming\GnuPG\S.gpg-agent.ssh' gehört
gpg-agent[1116]: gpg-agent (GnuPG) 2.2.28 started
gpg-agent[1116]: DBG: chan_0x00000290 -> OK Pleased to meet you
gpg-agent[1116]: DBG: chan_0x00000290 <- RESET
gpg-agent[1116]: DBG: chan_0x00000290 -> OK
gpg-agent[1116]: DBG: chan_0x00000290 <- GETINFO version
gpg-agent[1116]: DBG: chan_0x00000290 -> D 2.2.28
gpg-agent[1116]: DBG: chan_0x00000290 -> OK
gpg-agent[1116]: DBG: chan_0x00000290 <- OPTION allow-pinentry-notify
gpg-agent[1116]: DBG: chan_0x00000290 -> OK
gpg-agent[1116]: DBG: chan_0x00000290 <- OPTION agent-awareness=2.1.0
gpg-agent[1116]: DBG: chan_0x00000290 -> OK
gpg-agent[1116]: DBG: chan_0x00000290 <- GETINFO jent_active
gpg-agent[1116]: DBG: chan_0x00000290 -> OK
gpg-agent[1116]: DBG: chan_0x00000290 <- KEYWRAP_KEY --export
gpg-agent[1116]: DBG: chan_00000290 -> [ 44 20 af e5 15 32 b8 63 27 c1 5c b7 79 9d 29 c9 ...(2 byte(s) skipped) ]
gpg-agent[1116]: DBG: chan_0x00000290 -> OK
gpg-agent[1116]: DBG: chan_0x00000290 <- HAVEKEY XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX
gpg-agent[1116]: DBG: chan_0x00000290 -> OK
gpg-agent[1116]: DBG: chan_0x00000290 <- KEYINFO XXXXXXXXXXXXXXXX
gpg-agent[1116]: DBG: agent_get_cache 'XXXXXXXXXXXXXXXX'.0 (mode 2) ...
gpg-agent[1116]: DBG: ... miss
gpg-agent[1116]: DBG: chan_0x00000290 -> S KEYINFO XXXXXXXXXXXXXXXX D - - - P - - -
gpg-agent[1116]: DBG: chan_0x00000290 -> OK
gpg-agent[1116]: DBG: chan_0x00000290 <- SETKEYDESC Sie+benötigen+ein+Passwort,+um+den+geheimen+OpenPGP+Schlüssel+zu+exportieren:%0A%22test+tester+<test@tester.de>%22%0A4096-Bit+RSA+Schlüssel,+ID+8AA0EF152FA1B2DB,%0Aerzeugt+2021-12-07.%0A
gpg-agent[1116]: DBG: chan_0x00000290 -> OK !!!!!!! LOOK HERE !!!!!!!
gpg-agent[1116]: DBG: chan_0x00000290 <- EXPORT_KEY --openpgp XXXXXXXXXXXXXXXX
gpg-agent[1116]: starting a new PIN Entry
gpg-agent[1116]: DBG: connection to PIN entry established
gpg-agent[1116]: DBG: chan_0x00000290 -> INQUIRE PINENTRY_LAUNCHED 1332 qt 1.1.1 - - - - 0/0 -
gpg-agent[1116]: DBG: chan_0x00000290 <- END
gpg-agent[1116]: DBG: agent_put_cache 'XXXXXXXXXXXXXXXX'.0 (mode 0) requested ttl=0
gpg-agent[1116]: DBG: agent_put_cache 'XXXXXXXXXXXXXXXX'.0 (mode 5) requested ttl=120
gpg-agent[1116]: DBG: chan_0x00000290 -> S CACHE_NONCE 42E3B874198B86CC86244AC2
gpg-agent[1116]: DBG: chan_0x00000290 -> Confidential data not shown
gpg-agent[1116]: DBG: chan_0x00000290 -> Confidential data not shown
gpg-agent[1116]: DBG: chan_00000290 -> [ 44 20 24 a6 fc 2d b0 58 a6 3d f0 69 bb fb 74 be ...(22 byte(s) skipped) ]
gpg-agent[1116]: DBG: chan_0x00000290 -> OK
gpg-agent[1116]: DBG: chan_0x00000290 <- KEYINFO XXXXXXXXXXXXXXXX
gpg-agent[1116]: DBG: agent_get_cache 'XXXXXXXXXXXXXXXX'.0 (mode 2) ...
gpg-agent[1116]: DBG: ... miss
gpg-agent[1116]: DBG: chan_0x00000290 -> S KEYINFO XXXXXXXXXXXXXXXX D - - - P - - -
gpg-agent[1116]: DBG: chan_0x00000290 -> OK
gpg-agent[1116]: DBG: chan_0x00000290 <- SETKEYDESC Sie+benötigen+ein+Passwort,+um+den+geheimen+OpenPGP+Unterschlüssel+zu+exportieren:%0A%22test+tester+<test@tester.de>%22%0A4096-Bit+RSA+Schlüssel,+ID+XXXXXXXXXXXXXXXX,%0Aerzeugt+2021-12-07+(Hauptschlüssel-ID+XXXXXXXXXXXXXXXX).%0A
gpg-agent[1116]: DBG: chan_0x00000290 -> OK !!!!!!! LOOK HERE !!!!!!!
gpg-agent[1116]: DBG: chan_0x00000290 <- EXPORT_KEY --openpgp --cache-nonce=42E3B874198B86CC86244AC2 3B3A4D3DD3EC7E7ECCFE3FAEAD001BBE181E30DF
gpg-agent[1116]: DBG: agent_get_cache '42E3B874198B86CC86244AC2'.0 (mode 5) ...
gpg-agent[1116]: DBG: ... hit
gpg-agent[1116]: DBG: agent_put_cache 'XXXXXXXXXXXXXXXX'.0 (mode 5) requested ttl=120
gpg-agent[1116]: DBG: chan_0x00000290 -> S CACHE_NONCE 42E3B874198B86CC86244AC2
gpg-agent[1116]: DBG: chan_0x00000290 -> Confidential data not shown
gpg-agent[1116]: DBG: chan_0x00000290 -> Confidential data not shown
gpg-agent[1116]: DBG: chan_00000290 -> [ 44 20 b0 0f 61 38 20 51 64 7a fb f4 cc 04 98 50 ...(24 byte(s) skipped) ]
gpg-agent[1116]: DBG: chan_0x00000290 -> OK
gpg-agent[1116]: DBG: chan_0x00000290 <- [eof]
gpg-agent[1116]: DBG: agent_put_cache 'XXXXXXXXXXXXXXXX'.0 (mode 5) requested ttl=0
- Details (gpg output RSA PRIVATE-KEY 4096 Bit / SHA-512): ##############
C:\temp> gpg --s2k-cipher-algo AES256 --s2k-digest-algo SHA512 --s2k-mode 3 --s2k-count 65000000 --export-secret-keys | gpg --list-packets
off=0 ctb=95 tag=5 hlen=3 plen=1862
:secret key packet:
version 4, algo 1, created 1638902294, expires 0 pkey[0]: [4096 bits] pkey[1]: [17 bits] iter+salt S2K, algo: 7, SHA1 protection, hash: 2, salt: XXXXXXXXXXXXXXXX <= !!!!!!! LOOK HERE !!!!!!! protect count: 65011712 (255) protect IV: e4 7b de 46 29 39 1a 60 3f d4 1d cb 34 6e 24 df skey[2]: [v4 protected] keyid: 8AA0EF152FA1B2DB
off=1865 ctb=b4 tag=13 hlen=2 plen=28
:user ID packet: "test tester <test@tester.de>"
off=1895 ctb=89 tag=2 hlen=3 plen=596
:signature packet: algo 1, keyid XXXXXXXXXXXXXXXX
version 4, created 1638902294, md5len 0, sigclass 0x13 digest algo 10, begin of digest 3e 42 hashed subpkt 33 len 21 (issuer fpr v4 XXXXXXXXXXXXXXXX) hashed subpkt 2 len 4 (sig created 2021-12-07) hashed subpkt 27 len 1 (key flags: 03) hashed subpkt 9 len 4 (key expires after 2y0d0h0m) hashed subpkt 11 len 4 (pref-sym-algos: 9 8 7 3) hashed subpkt 21 len 4 (pref-hash-algos: 10 9 8 11) hashed subpkt 22 len 4 (pref-zip-algos: 2 3 1 0) hashed subpkt 30 len 1 (features: 01) hashed subpkt 23 len 1 (keyserver preferences: 80) subpkt 16 len 8 (issuer key ID XXXXXXXXXXXXXXXX) data: [4093 bits]
off=2494 ctb=9d tag=7 hlen=3 plen=1862
:secret sub key packet:
version 4, algo 1, created 1638902294, expires 0 pkey[0]: [4096 bits] pkey[1]: [17 bits] iter+salt S2K, algo: 7, SHA1 protection, hash: 2, salt: XXXXXXXXXXXXXXXX <= !!!!!!! LOOK HERE !!!!!!! protect count: 65011712 (255) protect IV: 19 56 82 26 50 28 c5 40 09 34 fd cc 9f 3f cc 0f skey[2]: [v4 protected] keyid: 9F3C86D8EEEA01AF
off=4359 ctb=89 tag=2 hlen=3 plen=572
:signature packet: algo 1, keyid XXXXXXXXXXXXXXXX
version 4, created 1638902294, md5len 0, sigclass 0x18 digest algo 10, begin of digest 23 ed hashed subpkt 33 len 21 (issuer fpr v4 XXXXXXXXXXXXXXXX) hashed subpkt 2 len 4 (sig created 2021-12-07) hashed subpkt 27 len 1 (key flags: 0C) hashed subpkt 9 len 4 (key expires after 2y0d0h0m) subpkt 16 len 8 (issuer key ID XXXXXXXXXXXXXXXX) data: [4094 bits]
--- cut here ---
Best regards ...