I could not find any good example of signing and verifying a file using PGP, I hope the following example could be useful.
I will use Bob and Alice to explain it.
1.Bob install Alice’s PGP Public key in his machine:
$ gpg --import <Key_Alice>-pub-sub.asc
2.Alice signs and encrypts a document (TestMessage.txt) using her PGP Private key :
$ gpg --output TestMessageSignedByAlice.txt -a --sign ./TestMessage.txt
--output : write output to FILE (TestMessageSignedByAlice.txt)
-a, --armor :output file should be in ascii format
--sign : document to sign and encrypt (TestMessage.txt)
The result is a document signed and encrypted (TestMessageSignedByAlice.txt) by Alice using her PGP private key.
3.Finally Bob verifies Alice’s signed document and decrypts document using Alice’s PGP Public Key. The original document content will be found in document TestMessageDecrypt.txt .
$ gpg --output TestMessageDecrypt.txt --decrypt ./TestMessageSignedByAlice.txt
--decrypt: file to verify signature and to decrypt (TestMessageSignedByAlice.txt)
--output : write output to FILE (TestMessageDecrypt.txt)
I used documentation from :
https://www.gnupg.org/gph/en/manual/x135.html
It works in a bit different way:
Alice uses her secret (private) key to sign a document, and Bob's public key to encrypt a document.
Bob uses his secret (private) key to decrypt document, and then Alice's public key to verify signature.
I am trying to export a secret key out of GPG for testing purpose and to facilitate the decryption of the private key, I'd like to export it with a simple s2k (s2k-mode 0) but all my attempt seem to fail. Here's how I proceed:
First export the key with GPG
$ gpg --export-secret-key --rfc4880bis --s2k-mode 0 --output privkey.bin D753C0F6
gpg: WARNING: using experimental features from RFC4880bis!
gpg: Note: simple S2K mode (0) is strongly discouraged
And then parse it with Julia with a code of my own
julia> bin2packet("privkey.bin")[1]
Secret-Key Packet
Length : 162, partial : false
----------------
Version : 4, Time : 2019-02-13T17:37:37
Algorithm : ECDSA public key algorithm [FIPS186] using scep256k1
scep256k1 Point(𝑥,𝑦):
f05314566c9bfc8d8cf463a7a01e7735245d588a60dd874f09a9636620abb314,
6bda245d43cbbe019ab1ad74316d675dd858cdd776820969bcc21bbccbd3a661
Specifics : Any[0xfe, "AES with 128-bit key [AES]", Any[3, "SHA1", "d6c9d217d64fb4ad", 31457296], "d0c6dd2e6320d5c4be5414161a7ef660806c531ff0c2a8e762a7b7898ce5e96c78708461c0f6777cc4c20a1ae9cd5f076c62120291d96306101d5e0e0386bac3b285fe0f8747"]
Be it with s2k-mode option set or not, I do get the same output, with an s2k specifier set to 3 (Iterate and Salt) [3, "SHA1", "d6c9d217d64fb4ad", 31457296] for mode, hash algorithm, salt and bit count respectively.
First of all, am I exporting the key correctly with GnuPG ?
Is GPG forcing s2k-mode 3 in some way and can it by bypassed?
GPG version for the record
$ gpg --version
gpg (GnuPG) 2.2.12
libgcrypt 1.8.4
I'm trying to decrypt a file but I get the following:
gpg <file name>
gpg: encrypted with 2048-bit RSA key, ID 4A83B612, created 2018-02-19
"user <email>"
gpg: decryption failed: secret key not available
When I list my keys using:
gpg --list-keys
Here is the result:
pub 2048R/0BBBBDB3 2018-02-19
uid user <email>
sub 2048R/4A83B612 2018-02-19
I understand that the sub key doesn't seem to be recognized.
To decrypt you need the private key. Have a look at https://www.gnupg.org/gph/en/manual/x110.html:
If you want to encrypt a message to Alice, you encrypt it using Alice's public key, and she decrypts it with her private key. If Alice wants to send you a message, she encrypts it using your public key, and you decrypt it with your key.
As the documentation states, only the recipient you specify by --recipient when encrypting can decrypt the message.
So in summary:
Encrypting uses the public key of the recicipient
Decrypting uses the private key of the recipient
I managed to have an output of gpg --list-secret-keys
I still can't decrypt the file though. Here is the output of gpg --output doc --decrypt doc.gpg:
gpg: encrypted with 2048-bit RSA key, ID 4A83B612, created 2018-02-19
"user " gpg: decryption failed: secret key not available
I'm trying to add a trust for a system account (to stop the nagging message when using it to encrypt data using that key). I've got subkeys setup and an offline master key:
$ gpg --edit-key AAAAAAAA
[...]
Secret key is available.
pub 4096R/AAAAAAAA created: 2015-09-09 expires: never usage: SC
trust: ultimate validity: ultimate
sub 4096R/BBBBBBBB created: 2015-09-09 expires: never usage: E
sub 4096R/CCCCCCCC created: 2015-09-09 expires: never usage: S
sub 4096R/DDDDDDDD created: 2015-09-09 expires: never usage: A
$ gpg --list-secret-keys
sec# 4096R/AAAAAAAA 2015-09-09
uid $NAME <$EMAIL>
ssb 4096R/BBBBBBBB 2015-09-09
ssb 4096R/CCCCCCCC 2015-09-09
ssb 4096R/DDDDDDDD 2015-09-09
If I want to sign a document I can use:
$ gpg --encrypt --sign --recipient AAAAAAAA --local-user CCCCCCCC! --output out.gpg in.gpg
Which uses exactly the specified subkey to sign (although in this case AAAAAAAA is actually unavailable so it couldn't be used in any case). However, if I try and do something similar to lsign another UID:
$ gpg --lsign-key --local-user CCCCCCCC! 'Mentor Root'
pub 4096R/DDDDDDDD created: 2015-09-14 expires: never usage: SC
trust: undefined validity: unknown
sub 4096R/EEEEEEEE created: 2015-09-14 expires: never usage: E
[ unknown] (1). $OTHER_NAME <$OTHER_EMAIL>
pub 4096R/DDDDDDDD created: 2015-09-14 expires: never usage: SC
trust: undefined validity: unknown
Primary key fingerprint: DDDD DDDD DDDD DDDD DDDD DDDD DDDD DDDD DDDD DDDD
$OTHER_NAME <$OTHER_EMAIL>
Are you sure that you want to sign this key with your
key "$NAME <$EMAIL>" (AAAA)
The signature will be marked as non-exportable.
Really sign? (y/N) y
gpg: secret key parts are not available
gpg: signing failed: general error
Key not changed so no update needed.
Is this just a hard limitation of gpg, or is there some step I am missing?
(Or equally possible, am I totally misunderstanding the intent of all this?)
EDIT: Is it simply that the CCCCCCCC subkey does not have the C capability? Is it possible to have a subkey with the C capability (it seems not from cursory searching)?
Only primary keys can have the certification capability C. You cannot sign (ceritfy) keys/user IDs with a subkey.
From RFC 4880, OpenPGP, 12.1 Key Structures:
In a V4 key, the primary key MUST be a key capable of certification.
The subkeys may be keys of any other type.
The math might well allow certification subkeys, but the standard prevents it.
I have a copy of the postgresql apt repository gpg key and would like to view the details of the gpg key as it comes in the file. Is this possible without importing it into a key ring?
There are several detail levels you can get when looking at OpenPGP key data: a basic summary, a machine-readable output of this summary or a detailed (and very technical) list of the individual OpenPGP packets.
Basic Key Information
For a brief peak at an OpenPGP key file, you can simply pass the filename as parameter or pipe in the key data through STDIN. If no command is passed, GnuPG tries to guess what you want to do -- and for key data, this is printing a summary on the key:
$ gpg a4ff2279.asc
gpg: WARNING: no command supplied. Trying to guess what you mean ...
pub rsa8192 2012-12-25 [SC]
0D69E11F12BDBA077B3726AB4E1F799AA4FF2279
uid Jens Erat (born 1988-01-19 in Stuttgart, Germany)
uid Jens Erat <jens.erat#fsfe.org>
uid Jens Erat <jens.erat#uni-konstanz.de>
uid Jens Erat <jabber#jenserat.de>
uid Jens Erat <email#jenserat.de>
uid [jpeg image of size 12899]
sub rsa4096 2012-12-26 [E] [revoked: 2014-03-26]
sub rsa4096 2012-12-26 [S] [revoked: 2014-03-26]
sub rsa2048 2013-01-23 [S] [expires: 2023-01-21]
sub rsa2048 2013-01-23 [E] [expires: 2023-01-21]
sub rsa4096 2014-03-26 [S] [expires: 2020-09-03]
sub rsa4096 2014-03-26 [E] [expires: 2020-09-03]
sub rsa4096 2014-11-22 [A] [revoked: 2016-03-01]
sub rsa4096 2016-02-24 [A] [expires: 2020-02-23]
By setting --keyid-format 0xlong, long key IDs are printed instead of the insecure short key IDs:
$ gpg a4ff2279.asc
gpg: WARNING: no command supplied. Trying to guess what you mean ...
pub rsa8192/0x4E1F799AA4FF2279 2012-12-25 [SC]
0D69E11F12BDBA077B3726AB4E1F799AA4FF2279
uid Jens Erat (born 1988-01-19 in Stuttgart, Germany)
uid Jens Erat <jens.erat#fsfe.org>
uid Jens Erat <jens.erat#uni-konstanz.de>
uid Jens Erat <jabber#jenserat.de>
uid Jens Erat <email#jenserat.de>
uid [jpeg image of size 12899]
sub rsa4096/0x0F3ED8E6759A536E 2012-12-26 [E] [revoked: 2014-03-26]
sub rsa4096/0x2D6761A7CC85941A 2012-12-26 [S] [revoked: 2014-03-26]
sub rsa2048/0x9FF7E53ACB4BD3EE 2013-01-23 [S] [expires: 2023-01-21]
sub rsa2048/0x5C88F5D83E2554DF 2013-01-23 [E] [expires: 2023-01-21]
sub rsa4096/0x8E78E44DFB1B55E9 2014-03-26 [S] [expires: 2020-09-03]
sub rsa4096/0xCC73B287A4388025 2014-03-26 [E] [expires: 2020-09-03]
sub rsa4096/0x382D23D4C9773A5C 2014-11-22 [A] [revoked: 2016-03-01]
sub rsa4096/0xFF37A70EDCBB4926 2016-02-24 [A] [expires: 2020-02-23]
pub rsa1024/0x7F60B22EA4FF2279 2014-06-16 [SCEA] [revoked: 2016-08-16]
Providing -v or -vv will even add some more information. I prefer printing the package details in this case, though (see below).
Machine-Readable Output
GnuPG also has a colon-separated output format, which is easily parsable and has a stable format. The format is documented in GnuPG doc/DETAILS file. The option to receive this format is --with-colons.
$ gpg --with-colons a4ff2279.asc
gpg: WARNING: no command supplied. Trying to guess what you mean ...
pub:-:8192:1:4E1F799AA4FF2279:1356475387:::-:
uid:::::::::Jens Erat (born 1988-01-19 in Stuttgart, Germany):
uid:::::::::Jens Erat <jens.erat#fsfe.org>:
uid:::::::::Jens Erat <jens.erat#uni-konstanz.de>:
uid:::::::::Jens Erat <jabber#jenserat.de>:
uid:::::::::Jens Erat <email#jenserat.de>:
uat:::::::::1 12921:
sub:-:4096:1:0F3ED8E6759A536E:1356517233:1482747633:::
sub:-:4096:1:2D6761A7CC85941A:1356517456:1482747856:::
sub:-:2048:1:9FF7E53ACB4BD3EE:1358985314:1674345314:::
sub:-:2048:1:5C88F5D83E2554DF:1358985467:1674345467:::
sub:-:4096:1:8E78E44DFB1B55E9:1395870592:1599164118:::
sub:-:4096:1:CC73B287A4388025:1395870720:1599164118:::
sub:-:4096:1:382D23D4C9773A5C:1416680427:1479752427:::
sub:-:4096:1:FF37A70EDCBB4926:1456322829:1582466829:::
Since GnuPG 2.1.23, the gpg: WARNING: no command supplied. Trying to guess what you mean ... warning can be omitted by using the --import-options show-only option together with the --import command (this also works without --with-colons, of course):
$ gpg --with-colons --import-options show-only --import a4ff2279
[snip]
For older versions: the warning message is printed on STDERR, so you could just read STDIN to split apart the key information from the warning.
Technical Details: Listing OpenPGP Packets
Without installing any further packages, you can use gpg --list-packets [file] to view information on the OpenPGP packets contained in the file.
$ gpg --list-packets a4ff2279.asc
:public key packet:
version 4, algo 1, created 1356475387, expires 0
pkey[0]: [8192 bits]
pkey[1]: [17 bits]
keyid: 4E1F799AA4FF2279
:user ID packet: "Jens Erat (born 1988-01-19 in Stuttgart, Germany)"
:signature packet: algo 1, keyid 4E1F799AA4FF2279
version 4, created 1356516623, md5len 0, sigclass 0x13
digest algo 2, begin of digest 18 46
hashed subpkt 27 len 1 (key flags: 03)
[snip]
The pgpdump [file] tool works similar to gpg --list-packets and provides a similar output, but resolves all those algorithm identifiers to readable representations. It is available for probably all relevant distributions (on Debian derivatives, the package is called pgpdump like the tool itself).
$ pgpdump a4ff2279.asc
Old: Public Key Packet(tag 6)(1037 bytes)
Ver 4 - new
Public key creation time - Tue Dec 25 23:43:07 CET 2012
Pub alg - RSA Encrypt or Sign(pub 1)
RSA n(8192 bits) - ...
RSA e(17 bits) - ...
Old: User ID Packet(tag 13)(49 bytes)
User ID - Jens Erat (born 1988-01-19 in Stuttgart, Germany)
Old: Signature Packet(tag 2)(1083 bytes)
Ver 4 - new
Sig type - Positive certification of a User ID and Public Key packet(0x13).
Pub alg - RSA Encrypt or Sign(pub 1)
Hash alg - SHA1(hash 2)
Hashed Sub: key flags(sub 27)(1 bytes)
[snip]
To verify and list the fingerprint of the key (without importing it into the keyring first), type
gpg --show-keys --with-fingerprint <filename>
Edit: on Ubuntu 18.04 (gpg 2.2.4) the fingerprint isn't show with the above command. Use the --with-subkey-fingerprint option instead
gpg --show-keys --with-subkey-fingerprint <filename>
I seem to be able to get along with simply:
$gpg <path_to_file>
Which outputs like this:
$ gpg /tmp/keys/something.asc
pub 1024D/560C6C26 2014-11-26 Something <something#none.org>
sub 2048g/0C1ACCA6 2014-11-26
The op didn't specify in particular what key info is relevant. This output is all I care about.
You may also use --keyid-format switch to show short or long key ID:
$ gpg2 -n --with-fingerprint --keyid-format=short --show-keys <filename>
which outputs like this (example from PostgreSQL CentOS repo key):
pub dsa1024/442DF0F8 2008-01-08 [SCA] │
Key fingerprint = 68C9 E2B9 1A37 D136 FE74 D176 1F16 D2E1 442D F0F8 │ honor-keyserver-url
uid PostgreSQL RPM Building Project <pgsqlrpms-hackers#pgfoundry.org> │ When using --refresh-keys, if the key in question has a preferred keyserver URL, then use that
sub elg2048/D43F1AF8 2008-01-08 [E]
The option --list-packets parses pgp data from a file and outputs its structure - in a very technical way, though. When parsing a public key, you can easily extract the user ids and the key ids of the signatures.
Be wary that this command only parses the data format, it does no validation of signatures or similar things.
To get the key IDs (8 bytes, 16 hex digits), this is the command which worked for me in GPG 1.4.16, 2.1.18 and 2.2.19:
gpg --list-packets <key.asc | awk '$1=="keyid:"{print$2}'
To get some more information (in addition to the key ID):
gpg --list-packets <key.asc
To get even more information:
gpg --list-packets -vvv --debug 0x2 <key.asc
The command
gpg --dry-run --import <key.asc
also works in all 3 versions, but in GPG 1.4.16 it prints only a short (4 bytes, 8 hex digits) key ID, so it's less secure to identify keys.
Some commands in other answers (e.g. gpg --show-keys, gpg --with-fingerprint, gpg --import --import-options show-only) don't work in some of the 3 GPG versions above, thus they are not portable when targeting multiple versions of GPG.
When I stumbled up on this answer I was looking for a way to get an output that is easy to parse. For me the option --with-colons did the trick:
$ gpg --with-colons file
sec::4096:1:AAAAAAAAAAAAAAAA:YYYY-MM-DD::::Name (comment) email
ssb::4096:1:BBBBBBBBBBBBBBBB:YYYY-MM-DD::::
Documentation can be found here.
pgpdump (https://www.lirnberger.com/tools/pgpdump/) is a tool that you can use to inspect pgp blocks.
It is not user friendly, and fairly technical, however,
it parses public or private keys (without warning)
it does not modify any keyring (sometimes it is not so clear what gpg does behind the hood, in my experience)
it prints all packets, specifically userid's packets which shows the various text data about the keys.
pgpdump -p test.asc
New: Secret Key Packet(tag 5)(920 bytes)
Ver 4 - new
Public key creation time - Fri May 24 00:33:48 CEST 2019
Pub alg - RSA Encrypt or Sign(pub 1)
RSA n(2048 bits) - ...
RSA e(17 bits) - ...
RSA d(2048 bits) - ...
RSA p(1024 bits) - ...
RSA q(1024 bits) - ...
RSA u(1020 bits) - ...
Checksum - 49 2f
New: User ID Packet(tag 13)(18 bytes)
User ID - test (test) <tset>
New: Signature Packet(tag 2)(287 bytes)
Ver 4 - new
Sig type - Positive certification of a User ID and Public Key packet(0x13).
Pub alg - RSA Encrypt or Sign(pub 1)
Hash alg - SHA256(hash 8)
Hashed Sub: signature creation time(sub 2)(4 bytes)
Time - Fri May 24 00:33:49 CEST 2019
Hashed Sub: issuer key ID(sub 16)(8 bytes)
Key ID - 0x396D5E4A2E92865F
Hashed Sub: key flags(sub 27)(1 bytes)
Flag - This key may be used to certify other keys
Flag - This key may be used to sign data
Hash left 2 bytes - 74 7a
RSA m^d mod n(2048 bits) - ...
-> PKCS-1
unfortunately it does not read stdin : /
For newer versions of gngpg version 2.2.8 and above:
If you want only want to get the short or long fingerprint of the key without importing the key and without redirecting stderr to stdout 2>&1:
(i.e. when you have scripts verifying the fingerprint before proceeding like with ansible)
I have included a way with --with-colons and one without depending on your scripting preferences.
To get short format key ID
short key id format (using --show-keys and --with-colons):
gpg --show-keys --with-colons keyfile.key | awk -F':' '$1=="pub"{print $5}'
short key id format (using --list-packets):
gpg --list-packets keyfile.key | awk '$1=="keyid:"{print$2}'
To get long format key ID
long key id format (using --show-keys and --with-colons):
gpg --show-keys --with-colons keyfile.key | awk -F':' '$1=="fpr"{print $10}'
long key id format (using --show-keys):
gpg --show-keys keyfile.key | sed -nr 's/^([ ]+)([0-9A-Z]{40}$)/\2/p'