Most of developers have had to generate a public/private key pair at one point or another. Often this is to create a certificate for a webserver, but it comes up for various reasons. Whenever I have to do this I am always extremely confused and amazed when it all works out, so in this post I am going to try to explain what is actually going on. Everything here will assume we are using RSA, which is complicated enough for one day.
Caveat: I am not an expert (or even close) in cryptography. If anything is wrong in this article please use the comments section to correct me. I am very aware that wrong information in this topic is often much worse than no information at all.
Using the openssl command you can do tons of stuff, so much stuff that sometimes it is very unclear what you are actually doing. Lets start with as basic as you can get.
Generate an RSA public/private key pair
As expained here
openssl genrsa -out privatekey.pem 1024
This creates a file called privatekey.pem. This is actually kind of confusing already, because that file actually contains both your private and public key.
What is this .pem file
This .pem file holds your private/public keys. It is in the PEM encoding, which is a human readable version of the DER encoding (see below). If you open one, typically you will see some kind of header like -----BEGIN RSA PRIVATE KEY----- followed by a series of characters and then a footer. One file can contain a series of objects like this. The mess of characters is a base64 encoded of ASN.1. As PEM is encoding as well as used a file extension, you will sometimes see a .key or .crt or .pub file that is in PEM format. A .pem extension itself doesn't really tell us much about what is in it. A PEM encoded file can contain a private/public key pair, just a public key or an entire certificate. The one we just generated just contains a private/public key pair
There are also DER files that can contain the same information except in binary format and without the headers and footers. I have run into .der files because iOS expects them. This link goes over some of the confusion points here. The openssl command can convert back and forth between this formats. DER encoding seems to be used more frequently (or perhaps all the time?) to hold certificates rather than just keys. Some .crt files are in DER format.
So now we have this .pem file with a private and public key, but if you want to do anything useful with this stuff you will need to be able to share only your public key. So the following extracts your public key
openssl rsa -in privatekey.pem -pubout > publickey.pub
This is a .pub file, but again, it's really just a PEM encoded file with only your public key. I believe the formats for these files are specified here
Do something useful
So at this point, you have come to a cross road. What can we do with these things?
- We can generate a certificate for some task.
- We use them directly them for some larger crypto scheme like digital signatures.
Certificates are useful if you are trying to setup a server for https or just need to work within the confines of a system that works best with certificates. For example, if you wanted to use your public key on iOS, the primitive functions exposed there expect a certificate even if you don't need any kind of chain of ownership. To generate a certificate you use openssl to create a Certificate Signing Request. In our case, we have already have a private/public key pair, so you would the following command
openssl req -out CSR.csr -key privatekey.key -new
You would then either submit this to an organization that would sign it for you, or sign it yourself to create a self-signed certificate.
openssl x509 -req -days XXX in CSR.csr -signkey privatekey.pem -our server.crt
Ultimately if this was your goal, you could have done everything up to now (except extract the public key) in one step:
openssl req -x509 -newkey rsa:2048 -keyout privatekey.pem -out cert.crt -days XXX
See this link for a breakdown of this command and how to not require a password.
By the way, as mentioned briefly above, if you want to do anything involving a public/private key on iOS, you are going to want a self signed certificate in DER form. This link explains how to do this from scratch or from the .pem file we created in the first step. Keep in mind that you have a few options on iOS, but if you don't want a solution that involves bundling openssl with your app, you need the self signed der file so you can use Apple's builtin functions. If you just want to verify a signed cert, I will go over that below.
Technically to use a public key on iOS you basically need to get your key into a SecKeyRef. There are various ways to do this, see here and here and this pod. If you just need to verify a signature, look at the first link. This link doesn't show how to load the certifcate, but shows both signing and verifying. You may need to tweak the functions and constants referring to SHA1 if you want to use SHA256.
You can always read the Apple docs for more concrete information.
Verify a signature on iOS
Use keys directly
Without a certificate (or with one) you can still create digital signatures for documents and verify them as well as encrypt and decrypt documents. You just use your private key to sign and other people use your public key to verify the signature (or someone else encrypts a document with your public key and you decrypt it with your private key). You can do this in Python using the M2Crypto, PyCrypt or rsa libraries.
One thing to keep in mind- with RSA there is usually a "textbook" conceptual way to do things that involves the pure math, and then the safe, blessed implementation schemes. Something that really bit me once was that PyCrypt implements both a "textbook" version of RSA signatures and the two official signature schemes (RSASSA-PSS and RSASSA-PKCS1-v1_5). Apparently the "textbook" one is not safe at all. See my comment here. The difference between the "textbook" version and the two official schemes has to do with extra padding (or encoding) done between hashing and signing that prevents certain types of attacks. You can see technical details of the RSASSA-PCKS1-v1_5 here. One interesting thing to note there is that scheme hashes your document with a particular hash function (that you can specify) and then encodes which hash function was used as part of the padding before it actually signs. This is why depending on the api you might need to hash your document first and then pass a symbol indicating which hash function you used to the sign or verify method. RSASSA-PSS is newer and seems to be generally recommended- but ultimately either is safer than naively hashing your document (with a SHA family function) and encrypting it with your RSA key (which is what I thought I could do after reading about digital signatures).
Thanks for reading, please leave any comments or corrections.