Sometimes I need to encrypt some stuff but do not want to install PGP or GPG. I typically use OpenSSL for this kind of thing and have written a simple frontend script to achieve strong password based encryption using OpenSSL. Sometimes you need public / private key encryption though, below will show you how to do it using just OpenSSL.
Public/Private key encryption is a method used usually when you want to receive or send data to thirdparties. The system requires everyone to have 2 keys one that they keep secure – the private key – and one that they give to everyone – the public key. Data encrypted using the public key can only ever be unencrypted using the private key. This method of encryption that uses 2 keys is called asymmetric encryption.
So by example if Person A want to send Person B data in a secure fashion she just have to encrypt it with Person B’s public key, only Person B can then open the file using her private key. There are other advantages to this kind of encryption. If I met you in person and gave you my public key, I can send you something electronically using my private key to encrypt it, if the public key you have can decrypt that data then you can trust that it was sent by me, it’s mathematical proof of identity. This is the basis for Digital Signatures.
Using OpenSSL on the command line you’d first need to generate a public and private key, you should password protect this file using the -passout argument, there are many different forms that this argument can take so consult the OpenSSL documentation about that.
$ openssl genrsa -out private.pem 1024
This creates a key file called private.pem that uses 1024 bits. This file actually have both the private and public keys, so you should extract the public one from this file:
$ openssl rsa -in private.pem -out public.pem -outform PEM -pubout
You’ll now have public.pem containing just your public key, you can freely share this with 3rd parties.
You can test it all by just encrypting something yourself using your public key and then decrypting using your private key, first we need a bit of data to encrypt:
$ echo 'too many secrets' > file.txt
You now have some data in file.txt, lets encrypt it using OpenSSL and the public key:
$ openssl rsautl -encrypt -inkey public.pem -pubin -in file.txt -out file.ssl
This creates an encrypted version of file.txt calling it file.ssl, if you look at this file it’s just binary junk, nothing very useful to anyone. Now you can unencrypt it using the private key:
$ openssl rsautl -decrypt -inkey private.pem -in file.ssl -out decrypted.txt
You will now have an unencrypted file in decrypted.txt:
$ cat decrypted.txt<br> too many secrets
All of these examples use the RSA encryption method, some hard core mathematical information about it here.
There are a fair few limitations to this approach – it will only encrypt data up to the key size for example. And you really should never encrypt english plain text using a method like this. You’d use this to safely encrypt a random generated password and then aes encrypt the actual text you care about. Look in the comments for examples of that.
I’ve yet to try this. You say that the encrypted file is binary junk, one of the nice things about GPG/PGP is that you can ascii armour it, so your binary junk is now ascii junk – making it more resilient when sending via email. I don’t see anything like this in openssl’s man page. Is there such functionality to you knowledge?
yeah rsautl can’t do ASCII mode, the other encryption methods in openssl can though – the linked crypt script has that option.
All mail clients though have sorted out attaching binary data without options though, the mail clients mime encodes data, seems more appropriete for the mail clients to make the data SMTP friendly to me anyway.
Thanks! I’ve been looking all over for this!
If I have some pretty big file to encrypt, the above method is not good enough. The best way to do that is to encrypt the file using secret key and then to encrypt secret key using public/private pair of keys. My question is how can I encrypt my big file with secret key using openssl?
Basically, it boils down to this:
— Generate secretkey:
“dd if=/dev/random of=secretkey bs=1k count=1”
— Symmetric encryption:
“openssl enc -blowfish -pass file:secretkey < bigfile > bigfile.bf”
— Symmetric decryption:
“openssl enc -d -blowfish -pass file:secretkey < bigfile.bf > bigfile”.
Who dislikes the idea of binary junk, look at converters/base64.
Your steps above works like charm. I have one more question.
Is there a way to create a secret file like above on the windows environment? Do let me know.
Would there be any issues with using a real cert (like one issued for email from Verisign)?
It only uses the keys, not the certificates so Verisign and co doesn’t come into play.
Ok..I tried it with a real cert I exported from thunderbird that was issued to me from Verisign…
As a test I did the following…
1. Exported my certificate from thunderbird as a pkcs12 (.p12)
formatted file (its the only format it will let me export it as)
2. Converted it to a PEM formatted file
openssl pkcs12 -clcerts -in cert.p12 -out cert.pem
3. Extracted the public key
openssl rsa -in cert.pem -out public.pem -outform PEM -pubout
4. Tried to encrypt a file using the public key
openssl rsautl -encrypt -inkey cert.pem -pubin -in test.pdf -out
RSA operation error
1047:error:0406D06E:rsa routines:RSA_padding_add_PKCS1_type_2:data too
large for key size:rsa_pk1.c:151:
I’m missing something fundamental somehow…any help would be greatly
I am having the same issues. Did you have any luck with encrypting or signing using rsautl?
you’ve two options:
1) encrypt the file in chunks smaller than the max size
2) encrypt the file using something like password based approach as I mention in the first paragraph, then use public/private key encryption to send the password.
It’s just a “feature” of the algorithm that it has a maximum block size.
Doug, maybe I’m way off, but you did:
openssl rsautl -encrypt -inkey cert.pem -pubin -in test.pdf -out
but according to the rsautl man page, the pubin option tells openssl that cert.pem is an RSA public key. If you’re going to use your certificate, I think you should be using the certin option instead of the pubin option.
Doug, seems I jumped the gun on my last post. R.I.Pienaar is correct in his statements. If all you’re trying to do is verify being able to use your cert, just try a file “smaller than the max size”. For a 1024-bit key (typical for certs?), I think it can encrypt only up to 1024 bits (128 bytes).
Makes me wonder though: how does an email program encrypt an email that’s larger than the “max size” associated with the certificate/key? Does it really break the email up into smaller chunks???
Thanks for your comments, I’ve seen some code in PHP for encrypting larger files and they do literally run the encryption several times – once per chunk – it sux a bit, there are more suited encryption methods though for larger chunks of data.
In reply to Greg,
I think the method used in email is to encrypt the body of the email with a symmetric algorithm using a totally random ‘session’ key which is only a few dozen bytes long. — RSA then encodes that session key.
That way you can CC the same encrypted message to ten different people with ten different public/private key pairs without having to send ten encrypted duplicates of the whole message.
so the RSA utility doesn’t need to process long messages — it’s only intended for encrypting the keys that are used with other algorithms.
Please help me.
I Understand how to create pair Public – Private keys. But I cannot understand how to create certificate for this keys (x.509 certificate for digital sign). Could you help me and explain?
Thanks for the post! For the user asking (back in 2006…) about using certificates, looks like the openssl “pkeyutl” command is required, which works in a similar way to “rsautl”.
It appears that pkeyutl, though documented on OpenSSL’s site, is not available even in the latest version (0.9.8k).
Perhaps it’s in the 1.0Beta…
I have created a bash script for encrypting large file/folder based on this post as well ideas suggested by those who left comments.
Any feedback and comments (except spams) are welcome.
I had the same issue… I had to encrypt some dump files (partition data) and got the same error:
“…too large for key size”
Now I encrypt the data using:
openssl enc -aes-256-cbc -pass file:[rsa private key] -in test.txt -e -salt -out test.ssl
That shoudl do the work. But make sure to keep the RSA private key safe! Store it on a encrypted partition like I did..
“openssl enc -aes-256-cbc -pass file:[rsa private key] -in test.txt -e -salt -out test.ssl”
That command is doing symmetric encryption. It’s not using your rsa private key as an actual key, it’s just using the raw bytes from that file as a password. You could replace it with any file and it’d do the same thing. For example, this would be just as effective;
“openssl enc -aes-256-cbc -pass file:random-image.jpg -in test.txt -e -salt -out test.ssl”
The problem with using rsautl is it can only encrypt things smaller than the size of the key minus 11 bytes. Not very useful.
Malone is on the right track but of course his example doesn’t actually work. Here is a working example:
openssl enc -aes-256-cbc -pass file:$HOME/.ssh/id_rsa -in test.txt -e -salt -out test.ssl
I need to create to sign and encrypt a file and create CMS objects (DER encoded) according to RFC3852 with X.509v3 certificates:
– Signed-Data (Digest Alg: SHA1; Encryption Alg: RSA) with separate sign and certificate(chain) included
– Encrypted-Data (Encryption Algoritm: des-ede3-cbc)
Can I do this with OpenSSL ? Are there any tools / scripts available to accomplish this?
I used OpenSSL smime to sign a file, but I am unable to encrypt it with the public key and create the appropriate CMS object with the Signed-Data encapsulated.
Can anyone please help me to accomplish this?
too many secrets = setec astronomy
P.S. Nice post I found it usefull, Thanks
thanks you clarified me that the “private key” contains the public too
To encrypt/decrypt files of arbitrary size using asymmetric (public) key cryptography you need to use S/MIME encoding:
1) generate the key pair
openssl req -x509 -days 10000 -newkey rsa:2048 -keyout rsakpriv.dat -out rsakpubcert.dat -subj ‘/’
This makes a 2048 bit public encryption key/certificate rsakpubcert.dat and a matching private decryption key rsakpriv.dat. The -days 10000 means keep it valid for a long time (27 years or so). You will be asked (twice) for a PEM passphrase to encrypt the private key. If you do not wish to encrypt it, pass the -nodes option. The public key can be distributed to anyone who wants to send you data. How you handle PKI is up to you.
2) encrypt data
openssl smime -encrypt -aes256 -binary -outform D -in -out rsakpubcert.dat
This makes a DER-encoded binary file of the input data using the public key.
2) decrypt data
openssl smime -decrypt -inform D -binary -in -inkey rsakpriv.dat -out
This decrypts the previously-encrypted data. You will be asked for the PEM passphrase you entered in step 1, assuming you did not pass the -nodes option.
If you want base-64 encoding use -inform/-outform P to get PKCS7 encapsulation.
Arrgh, the filenames were swallowed by the commenting software: Again:
openssl smime -encrypt -aes256 -binary -outform D -in (input filename) -out (output filename) rsakpubcert.dat
openssl smime -decrypt -inform D -binary -in (input filename) -inkey rsakpriv.dat -out (output filename)
Smime generate large file, so I use two files:
head -c 128 /dev/random > rnd.key
openssl rsautl -encrypt -inkey rsakpubcert.dat -certin -in rnd.key -out encrnd.key
tar -cz files | openssl enc -e -blowfish -pass file:rnd.key | dd of=files.tar.gz.bf
openssl rsautl -decrypt -inkey rsakpriv.dat -in encrnd.key -out rnd1.key
openssl enc -d -blowfish -pass file:rnd1.key -in files.tar.gz.bf | tar -zx
Man…. This post is 11 years old, and still THE best description, and easy to understand, with working examples I could found.
Thank You 🙂