Skip to content

Instantly share code, notes, and snippets.

@kennwhite
Last active January 16, 2024 15:47
Show Gist options
  • Star 26 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save kennwhite/9918739 to your computer and use it in GitHub Desktop.
Save kennwhite/9918739 to your computer and use it in GitHub Desktop.
OpenSSL command line recipe for multi-public key file encryption. Any single private key paired to one of the public keys can decrypt the file.
#!/usr/bin/env bash
#
# Example of multiple key AES encryption for text files using the openssl v. 0.9.8+ command line utility
# Uses n public certs as key for MIME PKCS envelope, any individual private key can decrypt.
#
# If standard RSA ssh keys exist, these can be converted to public certs as well (and ssh keys can decrypt)
#
# To sign (and verify) the encrypted file, one of the private keys is required, see:
# http://www.openssl.org/docs/apps/smime.html#EXAMPLES for openssl smime examples
# or http://www.openssl.org/docs/apps/cms.html#EXAMPLES for cms utility (OpenSSL v. 1.0+)
#
# Author: Kenneth White
# Released under the terms of the MIT license: http://en.wikipedia.org/wiki/MIT_License
# Basically: Feel free to use, just give credit please
#
# Alice runs this locally, then publishes/distributes her self-signed public cert (key stays private)
# Optionally, if local private key passphrase is required remove: -nodes
openssl req -x509 -newkey rsa:4096 -days 3650 -nodes -subj "/C=US/ST=*/L=*/O=*/OU=*/CN=Alice/" -keyout alice.key -out alice.pub
# Ditto for Bob...
openssl req -x509 -newkey rsa:4096 -days 3650 -nodes -subj "/C=US/ST=*/L=*/O=*/OU=*/CN=Bob/" -keyout bob.key -out bob.pub
# Ditto for Frank...
openssl req -x509 -newkey rsa:4096 -days 3650 -nodes -subj "/C=US/ST=*/L=*/O=*/OU=*/CN=Frank/" -keyout frank.key -out frank.pub
# If you wanna get crazy, Carol can use an existing SSH private key to generate a public cert (and decrypt w/ her ssh key)
openssl req -x509 -new -key ~/.ssh/id_rsa -days 3650 -nodes -subj "/C=US/ST=*/L=*/O=*/OU=*/CN=Carol/" -out carol.pub
# Central secrets repo
echo 'All our secretz are belong to us' > secrets.txt
echo 'Germans *love* David Hasselhoff!' >> secrets.txt
cat secrets.txt
# Encrypt it with multiple public certs (PKCS PEM base64 text format) in aes256 cbc mode
#
openssl smime -encrypt -aes256 -in secrets.txt -out secrets.txt.enc -outform PEM bob.pub alice.pub frank.pub carol.pub
cat secrets.txt.enc
# secrets.txt.enc file is safe to distribute
# Bob, Alice, Frank or Carol can now decrypt it with their private keys (SSL or SSH)
# Optionally: -out secrets.decrypted.txt
#
openssl smime -decrypt -in secrets.txt.enc -inform PEM -inkey alice.key
@ayush191992
Copy link

how can we achieve this through open ssl apis
openssl smime -encrypt -aes256 -in secrets.txt -out secrets.txt.enc -outform PEM bob.pub alice.pub frank.pub carol.pub

@burner
Copy link

burner commented May 21, 2021

@ayush191992 I was asking myself the same thing https://gist.github.com/burner/4d87d1421e39627f84316bc2892e6103

As the openssl uses the library, I took the smime app from openssl and removed everything that was not relevant to this task.

@kennwhite
Copy link
Author

@burner (and anyone else reading this): please don't use this for anything important. Among the (many) reasons, a) this uses unauthenticated CBC mode (you want AEAD, probably GCM at a minimum), b) you really want a proper modern single-message multi-recipient encryption scheme, and c) there's almost surely some serious security bugs in this ancient MIME implementation. Here, the mechanism is a single shared symmetric (AES) message data encryption key (DEK) protected using public key (RSA) envelope encryption, distributed in multiple wrapped forms, once for each public key. The recipients' RSA public keys are key encryption keys (KEKs).

But really, just don't use this for anything important.

@burner
Copy link

burner commented May 21, 2021

@kennwhite so how would that practically look when using the openssl cli?

@kennwhite
Copy link
Author

@burner I don't have the energy to try to wrangle the openssl command line tool to cough up the right incantation, but in 2021 you probably want something like age (https://github.com/FiloSottile/age). Might also take a look at magic wormhole (https://magic-wormhole.readthedocs.io/en/latest/welcome.html) for a different (painless) way to securely send a file to recipients. And if you're building from API as I understood your and the parent comment, libsodium Box & Secretbox would almost certainly be a better option for building blocks than openssl.

@burner
Copy link

burner commented Mar 22, 2023

for reference the dlang lib can be found here https://github.com/symmetryinvestments/smimeasym

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment