DISCLAIMER: Author is not an expert in cryptography (he is not an expert in anything really). Use this stuff at your own risk. If you find bugs or inaccuracies, please create an issue or PR on the github repository.

GPG basics

The GNU Privacy Guard, also known as GnuPG or simply GPG, is a popular open source OpenPGP (RFC4880) implementation. The system is widely trusted for securing integrity and confidentiality of internet communications through various cryptographic methods. GPG is used in Debian and Redhat to verify downloads from package managers (apt, yum) and people like Edward Snowden and Glenn Greenwald use it to encrypt confidential emails.

Public key crypto

Like most modern crypto systems, GPG makes use of public key methods. You can easily generate a personal keypair which consists of a private key and corresponding public key.

pubkey

Your private key is to be kept secret and needed to sign or decrypt messages. The corresponding public key should be made available to anyone that needs to verify your signature, or encrypt messages which can only be decrypted by you.

Once we have someone’s public key, we can send them secure messages and verify their signatures. However how do we find and authenticate the public key of a person or server if we have not talked to them before?

Web of trust

The complexity in public key systems derives from authenticating public keys. If we can not trust our communication channel to be safe, we can only be sure that a public key belongs to given person if it has been signed by someone that we do trust.

The major difference between GPG and PKI systems (such as HTTPS) is how we authenticate public keys. HTTPS is based on a system with Certificate Authorities (CA). Anyone can create a keypair for any domain/personal name, however we only trust public keys which have been signed by an official CA. This CA is typically a commercial vendor which verifies your identity (e.g. via a copy of your passport) and then uses their own keypair to sign a certificate containing your public key and your personal name / email / domain.

trust

GPG uses a different system which does not distinguish between peers and authorities. In GPG, anyone can sign another persons key. The GPG user determines which peers they choose to trust in their personal keyring. For new peers, the GPG software helps you figure out which of your current peers has verified the identity of the new peer, perhaps indirectly via a third or fourth peer, and so on: a “web of trust”.

The easiest way to exchange public keys and key signatures is via a keyserver. GPG is compatible with existing PGP key servers. These servers mirror each other so most keys are available on either one. This package automatically retrieves keys and signatures via the gpg_recv function.

GPG keyservers do not need HTTPS. One should only trust GPG keys on basis of GPG signatures, regardless of how they were obtained. For this reason it is also valid to share GPG public keys via e.g. a website or email.

Your keyring

It is important to know which version of GPG you are running and where your home dir is. Your home directory contains your configuration and the keyrings. GPG defaults to your system keyring, which is the same as the gpg command line utility and system package manager use.

str(gpg_info())
List of 5
 $ gpgconf: chr "/usr/local/bin/gpgconf"
 $ gpg    : chr "/usr/local/Cellar/gnupg@2.2/2.2.29/bin/gpg"
 $ version:Class 'numeric_version'  hidden list of 1
  ..$ : int [1:3] 2 2 29
 $ home   : chr "/Users/jeroen/.gnupg"
 $ gpgme  :Class 'numeric_version'  hidden list of 1
  ..$ : int [1:3] 1 16 0

Use gpg_restart to switch to another home directory, e.g. for a client which uses its own configuration and keyrings. For this example we store keys in a temporary directory.

gpg_restart(home = tempdir())
gpg (GnuPG) 2.2.29
libgcrypt 1.9.3
Copyright (C) 2021 Free Software Foundation, Inc.
License GNU GPL-3.0-or-later <https://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: /Users/jeroen/.gnupg
Supported algorithms:
Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
        CAMELLIA128, CAMELLIA192, CAMELLIA256
Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2

Use gpg_list_keys() to see the current contents of your keyring. It is empty to start with:

gpg_list_keys()
[1] id    name  email
<0 rows> (or 0-length row.names)

Generate keys

Use gpg_keygen() to generate a new public private keypair:

(mykey <- gpg_keygen(name = "Jerry", email = "jerry@gmail.com"))
[1] "A9DEF281EDFD0CCC"
gpg_list_keys()
                id  name           email
1 A9DEF281EDFD0CCC Jerry jerry@gmail.com

Import from keyserver

Use the gpg_recv function to download a given key and all available signatures for this key from a keyserver. For example let’s import the public key from Michael Rutter which is used to sign the Ubuntu r-base packages from CRAN:

gpg_recv(id ="51716619E084DAB9")
Searching: https://keyserver.ubuntu.com
     found   imported    secrets signatures    revoked 
         1          1          0          0          0 
(keyring <- gpg_list_keys())
                id           name              email
1 A9DEF281EDFD0CCC          Jerry    jerry@gmail.com
2 51716619E084DAB9 Michael Rutter marutter@gmail.com

Note that for imported keys, we do not have the private key:

(secring <- gpg_list_keys(secret = TRUE))
                id  name           email
1 A9DEF281EDFD0CCC Jerry jerry@gmail.com

Import from file

The gpg_import function reads an armored GPG key from a file or URL:

gpg_import("https://stallman.org/rms-pubkey.txt")
     found   imported    secrets signatures    revoked 
         1          1          0          0          0 

However this file does not contain any signatures for this key. If we import it from a keyserver we also get the signatures:

(rms_id <- gpg_list_keys("rms")$id)
[1] "2C6464AF2A8E4C02"
gpg_recv(rms_id)
Searching: https://keyserver.ubuntu.com
     found   imported    secrets signatures    revoked 
         1          0          0        199          0 
gpg_list_signatures(rms_id)
                 id           timestamp             name       email success
1  2C6464AF2A8E4C02 2013-07-20 18:32:38 Richard Stallman rms@gnu.org    TRUE
2  624DC565135EA668 2013-07-20 18:37:45                                FALSE
3  F05DDAE40371FCE5 2013-09-15 23:18:46                                FALSE
4  231696C3EAE0078A 2013-09-24 23:15:58                                FALSE
5  7B585B30807C2A87 2013-09-28 22:59:04                                FALSE
6  7CEF29847562C516 2013-09-29 04:59:53                                FALSE
7  520E0C8369B003EF 2013-08-20 12:31:55                                FALSE
8  D56E1B4C135D47A1 2013-08-29 13:36:03                                FALSE
9  31CC32CEF78F3EE4 2013-08-29 13:37:52                                FALSE
10 9439E86389D0AF41 2013-08-29 13:55:01                                FALSE
11 C5CFD08B22247CDF 2013-09-24 15:00:05                                FALSE
12 20B7283AFE254C69 2013-09-28 22:44:02                                FALSE
13 A866D7CCAE087291 2013-09-29 17:59:25                                FALSE
14 6D33FBF5B5E4C71A 2013-09-30 15:52:36                                FALSE
15 8916CADF8ACD372A 2013-10-02 13:17:17                                FALSE
16 8E549D02234CC324 2013-10-03 09:36:24                                FALSE
17 D605848ED7E69871 2013-10-04 11:03:23                                FALSE
18 758EAEC123F62336 2013-10-13 00:53:08                                FALSE
19 7B585B30807C2A87 2013-10-18 21:27:08                                FALSE
20 E4A6D8A25310523C 2013-10-23 02:53:11                                FALSE
 [ reached 'max' / getOption("max.print") -- omitted 185 rows ]

The signature only contains the key ID of the signer. You would need to download the corresponding pubkeys to actually verify these signatures.

Export a key

To export our newly created public key:

str <- gpg_export(id = mykey)
cat(str)
-----BEGIN PGP PUBLIC KEY BLOCK-----

mQGNBGD/ExMBDAC4T3xSz4gwLCTKbpIjoZB62nB8uRoABIQQpQzlRTlN26OV9NjK
EffNKHwcJrBXRp2zXtrG1UpIMsbiuzUA9A8ZnKYX+70Lsxa9Yz0IVJ4rD8DCNp5P
5pBTDlmKUCjXPaG2t3R/CwCHN0vh9W4qw3OWrT1beYT7Wc9OpE/JUWL1V9kHof+x
+yvRPcPeGuHMyAvNhCZ3w39hwpu3GlrMK+c9KByCfHI/nT6NuDelzdESDyo9JFD5
vgSq/gjIrq27eaUkI6mRvKHsN+hOv/ePLD9S4B46dL/Lafq2dlZinXSVL01X461J
uQ+bk04dtR0op21l8yHvgFaKi6E79YNFB+3KoUt9QG8h5lh+sCn6Xkp7MjBdyiu7
9gls9KMDi5lQ0S5/cEZ40ueuQiS6Gt/thi28rFR0uXTn2mSGrCx+6bvLPeWCrH/+
cOBfCItDameNHvcQyHTsMMV4gzMlofAr7Wd2DJADzTdpEhzepln7OumcO9M7agN8
MYMH4nAlYqPk+bkAEQEAAbQXSmVycnkgPGplcnJ5QGdtYWlsLmNvbT6JAdQEEwEI
AD4WIQTilVH0GZKoai1ueomp3vKB7f0MzAUCYP8TEwIbDwUJA8JnAAULCQgHAgYV
CgkICwIEFgIDAQIeAQIXgAAKCRCp3vKB7f0MzOcCDACKhu+KzCwz3oj2DtGLYxVh
kJbHagXDoWX9D6JhkVJvZ1HcqqekSQ5+XSAVZCXlFEG1+JEJW6eLIKLLjFmr9690
T7KFGXj+6tTO3sPw6W/r0xWWhkcw3G0F3vqS9PcnM7ChrWHV9gnWz4ML8QLMnUAH
NNLnUvH0J+DSsMNcz9yi7kG/T4qMC5T6DOqNXrEQdyqJ0m9lsCqJ5XX55lQq79MA
oToJgSjGLCbjeLfZD1gtQZgeqTl8OD5rFICaI/D8uCXWiz1mJz8Z3DW4+DWMJ5wh
cSI3ROC63ZSGniRX/jA7rbr2D6DCXyNP39A/5ZGRzmDGG9nlNpLYoOzzHLzHaVR+
jm9o1UEFOc5g97Ts0im68K9bWdK02T2d34GBdIjlpYndfBoCpNfWsZ/qB6C22HOR
JIyO+s4W+NM1TLidg8WcFlj5qUIOb7HKWRk7az0S6R9nCLMANzYBTqdB0ncfBFH7
pC7kUdR2xvlLe8a9D9YRpx0VSKcRrvgA+jcRjftarZ0=
=67Od
-----END PGP PUBLIC KEY BLOCK-----

If you also own the private key you can export this as well:

str <- gpg_export(id = mykey, secret = TRUE)
cat(str)
-----BEGIN PGP PRIVATE KEY BLOCK-----

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
=RnOR
-----END PGP PRIVATE KEY BLOCK-----

Delete a key

Delete a key from its ID or fingerprint. Let’s delete the RMS key:

gpg_delete('2C6464AF2A8E4C02')
[1] "2C6464AF2A8E4C02"
gpg_list_keys()
                id           name              email
1 A9DEF281EDFD0CCC          Jerry    jerry@gmail.com
2 51716619E084DAB9 Michael Rutter marutter@gmail.com

Digital Signatures

A digital signature is a mathematical scheme for demonstrating the authenticity of a digital message or document. If you sign a file using your personal secret key, anyone can verify that this file has not been modified (i.e. the hash matches the one in your signature) via your public key.

GPG signatures are widely used by Linux package managers such as apt to verify the integrity of downloaded files. Typically the public key is shipped with the OS, and the private key is owned by the repository maintainers. This way we can safely install software from any mirror or network.

Sign a file

Let’s use the private key we generated earlier to sign a file:

myfile <- tempfile()
writeLines("This is a signed message", con = myfile)
sig <- gpg_sign(myfile)
writeLines(sig, "sig.gpg")
cat(sig)
-----BEGIN PGP SIGNATURE-----

iQGzBAABCAAdFiEE4pVR9BmSqGotbnqJqd7yge39DMwFAmD/ExUACgkQqd7yge39
DMyc/Qv9HjEAOra6DW8z5C+Y51TGxje8FLhkjfhDs+rpTMIMA4HgN5o3eJODDO0L
eL+EvRaYPztl6C3WDqT7CnpXFaWQRkprk/hdc87wblEytP32m0GPJ0nfBE7VXgt+
JzWEFg2BSByKFcq+A+LWfdR4yGjc5dypTNRg/B295Zvkj08QxMOmGcouoJB3eWmS
bSad2hAJgzDZ4RQqdZG8ovTjYriWnENcfhtYYS6d0aHa+6N56VLgm+y6TTY3QGJX
xwFqwuSIhFb5XElTm7Cp5Ot9/Tia1brhPAgvhRxhvhLSWgOwrFoAA64KLZM3aU8F
iuHfElhfgNf3W9Qw5zT1TjmxoydQ5baJfNqP8NvbihSeHBi7XjqrNjmk9LytSSv0
lUMJzP5fj8ObED3RnCO9AlrXi06sXQfMC27kU/Md3UyxrhRuhatHVojo3r/MwYSw
b/CJSJ0nzkDBw+U3UxZcgbKrtLw60qdFgtXbmeNmt8S5bp2th4DhVJvyKLDDjerh
cUAx9DwH
=dDjY
-----END PGP SIGNATURE-----

You can also create a signed message which includes the data itself by setting mode to normal or clear, which is useful for email:

clearsig <- gpg_sign(myfile, mode = "clear")
writeLines(clearsig, "clearsig.gpg")
cat(clearsig)
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

This is a signed message
-----BEGIN PGP SIGNATURE-----

iQGzBAEBCAAdFiEE4pVR9BmSqGotbnqJqd7yge39DMwFAmD/ExUACgkQqd7yge39
DMw6YAv/ZuVH7n/OlG9kaS5OPtKR9I1D1kNkGf/+I2awrsM9p9iEekKjI5Mr4JXK
QxS7qf/sCcWEpwqcQu5X2MRZJpPaq+6zt6rcFPnjkJM66axll5hGt/7amNkPAYTO
mKmtbYejulhU1mhHLFyKYDM1gal9WFYy0RwKlW3DacVu1t02QRtO+sQRnlrL/yxs
s5WA/UrIyT1wx0t+teB9SePO5EG+oqG3OZyIveEmIpDunN73hYMieT59hdR5h+AB
Yr6lK8gB/BF3sc8SU1pxF6fAPcRfA/NxRy0Xk+xAKD2M7PUbLhQGQTRuq52prp/P
PpOAbDQHXKbSzpDXpQZCLEB1jwvA38ZqvmpOy5V4AFnaywrQRC4aah4TLuqD9oJi
JazeNWqGsN5pPncKFLAVMLmYJVDeHj+hGuSRX2rc6Uj/ZDDlQbk3k/3N3kZxEJlx
TCwEF2O0leYIMwIGZy3eiaMvOjsO8Vq3ZQQr96m6rLPhlY9RltSCjcojfF1auS/s
MlTVakA2
=QDGB
-----END PGP SIGNATURE-----

Verify a signature

The gpg_verify function will see if a signature is valid for any of the keys in the keyring:

gpg_verify("sig.gpg", data = myfile)
                               fingerprint           timestamp   hash pubkey success
1 E29551F41992A86A2D6E7A89A9DEF281EDFD0CCC 2021-07-26 21:55:01 SHA256    RSA    TRUE

If the signature is in clear or normal mode, the signature file contains both the message and signature:

gpg_verify("clearsig.gpg")
                               fingerprint           timestamp   hash pubkey success
1 E29551F41992A86A2D6E7A89A9DEF281EDFD0CCC 2021-07-26 21:55:01 SHA256    RSA    TRUE

Debian example

Let’s verify a Debian file. The Debian page on CRAN says the following:

The Debian backports archives on CRAN are signed with the key of Johannes Ranke (CRAN Debian archive) with key fingerprint 6212 B7B7 931C 4BB1 6280 BA13 06F9 0DE5 381B A480

Let’s import his key so that we can verify the Release file, which contains checksums for all files in the repository:

# take out the spaces
johannes <- "E19F5F87128899B192B1A2C2AD5F960A256A04AF"
gpg_recv(johannes)
     found   imported    secrets signatures    revoked 
         1          1          0          0          0 

If you don’t trust the CRAN homepage, you could check who has signed this key. You’d need to import the corresponding peer keys for more information.

gpg_list_signatures(johannes)
                id           timestamp           name                  email success
1 AD5F960A256A04AF 2016-11-16 01:18:06 Johannes Ranke johannes.ranke@jrwb.de    TRUE
2 2F0F4E14F649AF90 2016-11-16 01:29:16                                         FALSE
3 06F90DE5381BA480 2016-11-16 01:35:39                                         FALSE

Now lets verify the release files:

# Verify the file
library(curl)
Using libcurl 7.64.1 with LibreSSL/2.8.3
curl_download('https://cran.r-project.org/bin/linux/debian/buster-cran35/Release', 'Release')
curl_download('https://cran.r-project.org/bin/linux/debian/buster-cran35/Release.gpg','Release.gpg')
gpg_verify('Release.gpg', 'Release')
                               fingerprint           timestamp   hash pubkey success
1 AD7B5162BA456BE3526F8D92FCAE2A0E115C3D8A 2020-02-29 14:48:03 SHA512    RSA    TRUE

Looking good! We can trust the checksums in the Release file to be legitimate.

Anonymous Encryption

GPG uses public key encryption. You can use someone’s public key to encrypt a message or document, in a way that only the owner of the corresponding private key will be able to decrypt. This is a great way to send somebody highly confidential data.

Encrypt a message

For example we want to send an email Jeroen containing top secret information that may not be snooped by our ISP or email provider. First we import Jeroen’s public key using the ID as listed e.g. here:

jeroen <- '16C019F96112961CEB4F38B76094FC5BDA955A42'
gpg_recv(jeroen)
     found   imported    secrets signatures    revoked 
         1          1          0          0          0 
writeLines("Pizza delivery is on it's way!", "secret.txt")
msg <- gpg_encrypt("secret.txt", receiver = jeroen)
writeLines(msg, "msg.gpg")
unlink("secret.txt")
cat(msg)
-----BEGIN PGP MESSAGE-----

hQEMA4BQ/mdnc2saAQgAgE5nfsjFq411VGRL4J37EQQnrHeag9JGY2fm0n0XbRCK
c3clEfMd0q33Cz+1BAg+hYez/j5w48L1xbuZA7KebzgMVJPvDk2FGZFqTV6NZipq
5GNNNNenAHuiEQ2dqyLR/fQthdwL3OHfwZpUWNurk4N59jlSTo1ID+4VkhIXn4Df
jrXJd7/Jbwu+UIXyRYUEDN3jF+YIS2Fb2w1njIiUZZepXc6e/Pc1lz5dsQStckgd
6Sm1RI+LkioI+i9J+cmEZ9SOnxVxUsDoapNtJDyCHvZJBE++HzkmwpaUmUfcffuy
8EdTpWSSkEK7i0VV7kp2rkS4Qz4phiprYLTqCUnRctJaAR4oJP1m9A5WR1X8YJzM
hRo028Bxji0eLK7X4GKtifhDNnVqnmoy7Rp++TWIPnwFIo83Rnvu7eYcAL3GwX6n
9YWpgLEZpaZZqimekzCsOXatZboNyaV3oGxV
=6/S4
-----END PGP MESSAGE-----

Now you can safely send this message over any channel (email, twitter, etc). Nobody in the world besides Jeroen will be able to decipher this message (not even you).

Decrypt a message

Decrypting a message is just as easy. GPG will automatically find the correct private key from your keyring, or raise an error if you don’t have it. For example we will not be able to decrypt the message we created above for Jeroen

# This will error, we do not have this private key
gpg_decrypt("msg.gpg")
Error: GPGME verify signatures and decrypt message error: No secret key

To demonstrate decryption, we encrypt a message using our own keypair (for which we own the private key).

writeLines("This is a test!", "secret.txt")
msg <- gpg_encrypt("secret.txt", receiver = mykey)
writeLines(msg, "msg.gpg")
cat(msg)
-----BEGIN PGP MESSAGE-----

hQGMA6ne8oHt/QzMAQv/ePFtTdyY90dHkB/q7nrFErUPc+EVDobpXvvgX6h6mIRj
JGs1EWTDafiFTXCw44ox5l0kZy6lgflafNkAqbmV3GdM1APXJEvtXw3pN0B4HOU5
0CUayp68lAOrQVLqxMt/b7qerS4SERqpJsLwXsgUCkF62ci0MTsDM67f9+ox5g8k
5cwI2u5i0o3hi4pNveU6tDa//8F5oWi3ko6tpsxioZW9jxSlJFBXDSQALWmlJK5F
n2rArJta40MfxTW19ZFn7MPoOcpgUSKC16cNQRGdM4YcEmjRc0mFci7OpcDQ8vDx
F8L71NZ6aT2xOUsjhg5+Y9x4pPg/GD1v/pa0RxsCOtbbPdbSId2Au7ZpyLIci+Ww
ND5rmhaUOc4JbVN4JHlGpLwQk7sgW15Bf3prAQzqr5P/RFCupXq338BH7tJLzalR
aJ07Cw+yGDWj+7PWItkGcLXs3spq24T7qdHLlV0UccLHkvYF4tTgmC+qrMZZES5B
RgVMMUY51DMpZb80f/ZZ0kkB4gAeBetAGUAPcrujT/HrLiUCZ+Q9ZgITxWtObwAd
i6kayEpY9Aw5ty8dEwoAX5FoMUAjRqEt/zsyWFFaWNu6Y1MvNJn2OBLn
=Su4t
-----END PGP MESSAGE-----

Decryption is simple, given that we own the secret key for the message:

gpg_decrypt("msg.gpg")
[1] "This is a test!\n"

Authenticated Encryption

So we showed how to encrypt a message so that it can only be read by the receiver. But how does Jeroen verify the sender identity?

Sign and Encrypt

In signed encryption, also known as authenticated encryption, uses combined encryption and signing. The public key of the receiver is used to encrypt the message, and the private key of the sender to sign the message. This way the message is both confidential and the integrity of the sender can be checked and verified, only by the receiver.

msg <- gpg_encrypt("secret.txt", receiver = jeroen, signer = mykey)
writeLines(msg, "msg.gpg")
cat(msg)
-----BEGIN PGP MESSAGE-----

hQEMA4BQ/mdnc2saAQf/RcbWhAN75VPXcv2/AaWRzpmJINARn1QENteyL8DPT6i+
FEIrGGAuFQIHlglRkhXO8dkNODyUDIQkOEQoV/6vrl+2t3egGDEXhACvIcEOZ7li
wtr7lFJsIenQ62ICs5yr35ZTxV0TKQFOAjdLr/d2x0GAXhnTQXLNC3hZ5imphN5B
JTyMkxnwcwOqASiD3jBTg3ZpaDeUOT3dYVC3qKO+HX6B60E93rDfV0OEVwFGWbXf
wpMhCFDMAf8kDpRI9eHLQF6qReXn5kTlCVplpcLcyPBMy0UcxX/w/8A/cdKZcSgs
l1Bs69q5Z0Jd+L7/CvvuVF65AV6sdG64b7iksBJTBtLpAVTFVK9YAkHzFJiuSrmF
rrBuVmqe6mNvxL5Sd1vr7RDPv7uLEZJAVwRNezgeSmafWRazprD+kTaN7UoT1+SH
hTm/EEDAegL9HKJRUGNM2jJWLAEF5uu4xmSDOsbbAov2WtqAdRtFY9TPa9llYMgS
e38I1lYt06qZt+ajgn0KuPg1eHJyLjVgY8b9q2+E01NThlUgOcwQ9zuEWP5wHJ2Y
HulCGyA85gjUwBJn6jpahRKoBn+RqIPYlZj3qKdKXEOLvLfHXJ1HBfQPfF9c5+yM
fQvWjoBDL7cA6mN3FgfgxiUqynyoK6JLJqYRbpT5vA/6lD1qvfs5EnoDt09ctsXW
VM5SW45ZLoIEXpSZfbKwGVP+w0ZvzivlX+qe4CFZrCmSsi8Hed7X+Rxn4Rdw8Io1
13RbTjv3DNY8gv+2YAGZgpHtqDFY506zuGBpWVWTIJTQ7+xVtM6VXFqNBjt9GsJX
frZe/HT9fkZitl5WSNM97W+Rz5ClrETGa4wS4Gk/MVhm2REQ1L3RNTXcdU8Qkd33
oCsqtW7ipjUS/ZpqbyK0jmGXO3xy4eVoDpJQYsB30NDJiCUsIlEcqoNBGr6fnZ/A
zWKSPPJeJaogvpHGuNg/E/rtmFXJvoogjE8OjddopAWwAdt72ESt0n6GlJ6Hhc95
oIvLJ8wP3d8lu1171JfLPScT6DrzcawljRd5Yv5IgZbQ+4n/WQ==
=j4Wv
-----END PGP MESSAGE-----

Decrypt and Verify

If the encrypted message contains a signature, it will automatically be verified when the message is decrypted. The function raises an error otherwise.

For purpose of illustrating authenticated decryption, we encrypt and sign using our own key (which usually does not make sense):

msg <- gpg_encrypt("secret.txt", receiver = mykey, signer = mykey)
writeLines(msg, "msg.gpg")
gpg_decrypt("msg.gpg")
[1] "This is a test!\n"
attr(,"signer")
[1] "E29551F41992A86A2D6E7A89A9DEF281EDFD0CCC"

The signer fingerprint (if any) will be added as an attribute to the decrypted message.