thoughts/data/gpg-openssl.md
Tommy Skaug 805a34f937
All checks were successful
Export / Explore-GitHub-Actions (push) Successful in 2m19s
initial migration
2024-08-05 20:24:56 +02:00

126 lines
4.6 KiB
Markdown

## Key Takeaways
* PGP are replaceable with native OpenSSL RSA public key crypto
and AES-256 keys.
* This approach simplifies crypto operations, and only requires
OpenSSL which is widely available.
* Existing PGP keys stored in GnuPG work with OpenSSL via `gpgsm`.
## Introduction
The rabbit hole mission of mine to get rid of PGP continues.
Lately I have been looking into converting PGP keys from GnuPG to
OpenSSL. This way I can send encrypted data to people not using my
OpenSSL-only approach. After all, most people still depend on PGP
and it is the format they publish their public keys in.
## Exporting A PGP Public Key for Encryption Using OpenSSL
A PGP key cannot be directly read by OpenSSL, but GPG can natively
export to SSH and ssh-keygen to PKCS8:
```
gpg --export-ssh-key <key-id>! > /tmp/test.pub
ssh-keygen -f /tmp/test.pub -e -m PKCS8 > /tmp/test.pem
```
The above pubkey can be used to encrypt data with OpenSSL as shown
on my [contact page](https://contact.252.no):
```
KEY=`openssl rand -hex 32` IV=`openssl rand -hex 16`
ENCRYPTED_KEY_B64=`openssl pkeyutl -encrypt -pubin -inkey /tmp/test.pem -pkeyopt rsa_padding_mode:oaep <<< $KEY|base64`
BLOB=`openssl enc -aes-256-cfb -a -e -K ${KEY} -iv ${IV} -in some-file`
echo "PKCS11-VAULT;aes-256-cfb;rsa_padding_mode:oaep;$ENCRYPTED_KEY_B64:$IV:$BLOB;" > encrypted.txt
```
The steps of the above are:
1. Create an initialization vector [1] and an encryption key
2. Encrypt the one-time key to test.pem (our exported PGP-key)
3. Encrypt `some-file` using the key and IV using 256 bits AES in CFB-mode
4. Format the output in my PV-format.
Store `encrypted.txt` for decryption in the next section.
## Exporting a PGP Private Key for Decryption Using OpenSSL
This part is a bit more complex. For the sake of an example, let
us say you received an encrypted blob with an IV and encrypted
key, using the approach shown in the former section. You have the
key stored in GnuPG.
`gpgsm` can export your private key to p12, which is readable for
OpenSSL [2].
First list your secret keys in the GnuPG store: `gpg
--list-secret-keys --with-keygrip`.
Convert the key to X.509 by: `gpgsm --gen-key -o
/tmp/temp.crt`. You need to fill the values requested:
* Select "existing key"
* Fill the keygrip from the GPG secret key listing. Make sure you
use the right key, since GPG generates several keys behind the
scenes (the encryption key)
* Fill the cn (this needs to be on the format "cn=...") and e-mail
* Accept the other values as empty and accept the creation
Now import the certificate into `gpgsm`: `gpgsm --import
/tmp/temp.crt`. When imported, find the key ID by: `gpgsm
--list-keys`.
Using the key ID, you can now export the key in p12-format.
```
gpgsm -o /tmp/$keyid.p12 --export-secret-key-p12 $keyid
openssl pkcs12 -in /tmp/$key.p12 -nodes -nocerts|tail -n +5 > /tmp/$key.key
```
You only need to do the conversion once and now have your key in
`/tmp/$key.key`. This should be secured accordingly, and have a
password set as is offered in the guidance by gpgsm.
The resulting `/tmp/$key.key` is usable for decrypting content
encrypted by the public key. To decrypt the data in `encrypted.txt`:
```
IFS=';' read IDENTIFIER ALGORITHM PADDING_MODE ENCRYPTION_BLOBS SIGNATURE < encrypted.txt
for BLOB in ${ENCRYPTION_BLOBS[@]}; do
IFS=':' read ENCRYPTED_KEY_B64 IV TEXTFILE_ENC <<< $BLOB
ENCRYPTED_KEY=`printf $ENCRYPTED_KEY_B64 | base64 -d`
decrypted=false
DECRYPTED_KEY=`echo $ENCRYPTED_KEY_B64 |base64 -d | openssl pkeyutl -decrypt -inkey /tmp/$key.key -pkeyopt ${PADDING_MODE} 2> /dev/null` && decrypted=true
if [ $decrypted != false ]; then
TEXTFILE_DEC=`printf %s "$TEXTFILE_ENC"|base64 -d|openssl enc -$ALGORITHM -d -K "$DECRYPTED_KEY" -iv "$IV" |base64`
break
fi
done
echo $TEXTFILE_DEC
```
The above format supports encryption to multiple parties. It:
1. Reads the PV-format into variables
2. Loops through the encryption blobs (one pass if one recipient)
3. Decrypts the key with the private key generated from `gpgsm`
4. Using the IV and decrypted key, decrypts the content, which is
eventually the same as in the previous section's `some-file`
5. Prints the decrypted content
## Conclusion
It is possible to convert PGP keys to use with OpenSSL via `gpgsm`.
Since OpenSSL is more widely distributed and installed than GnuPG,
it is a method applicable in more environments.
Using OpenSSL instead of GnuPG provides more options, and reduces
the complexity of cryptography (since GnuPG has lots of options).
[1] https://stackoverflow.com/questions/39412760/what-is-an-openssl-iv-and-why-do-i-need-a-key-and-an-iv
[2] https://superuser.com/a/1414277