Generating and inspecting an RSA private key
In principle you generate an RSA key by finding two large prime numbers, p and q, and computing n = pq. You could, for example, generate random numbers by rolling dice, then type the numbers into Mathematica to test each for primaility until you find a couple prime numbers of the right size.
In practice you'd use a specialized program to find the primes and to wrap everything up in a format that software using the keys can understand. There are a lot of layers between the numbers p and q and the file that key generating software produces, and this post aims to peel back these layers a bit.
Here's an example of generating a private key taken from The OpenSSL Cookbook.
openssl genpkey -out fd.key -algorithm RSA \ -pkeyopt rsa_keygen_bits:2048 -aes-128-cbc
The genpkey function can be used for generating several kinds of public keys. The option -algorithm RSA tells it that we want an RSA key, but we could have asked for an elliptic curve key. As noted in the previous post, in practice public key encryption is used to transfer symmetric encryption keys, not messages per se. The flag -aes-128-cbc tells the software the we'd like to use AES encryption with a 128-bit key in CBC (cipher block chaining) mode.
When you press enter you'll see a flurry of dots and plus signs that show the progress of the software in generating and testing candidates for the primes p and q. Then you'll be prompted for a password to encrypt the private key you've just created.
If you open the fd.key file you won't see much:
% cat fd.key -----BEGIN ENCRYPTED PRIVATE KEY----- MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIdCZSKfkqh6kCAggA MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAECBBAqbtHXkZ+uqa3rvj6qKqbRBIIE ... U6QCPcWukFyUAghHdTfjKgoAEXfOEunALoaTF6LMPsd6 -----END ENCRYPTED PRIVATE KEY-----
This is just base 64-encoded data.
The data is encoded in two senses. It is encoded in a non-secret way, expressed in a standardized data structure, then encoded in the sense of being encrypted. The openssl command pkey will undo both levels of encoding to let us see the contents of the file.
Here's what this produces.
Private-Key: (2048 bit, 2 primes) modulus: 00:a7:b8:39:80:0b:18:d9:db:c1:a3:c1:3a:92:89: ... 7a:c5 publicExponent: 65537 (0x10001) ... prime1: 00:dc:8c:27:e6:7f:1c:11:d4:9c:8c:33:bf:07:57: ... 97:5f:8c:4c:44:23:d2:85:f9 prime2: 00:c2:ae:20:80:87:da:d0:a1:66:8f:2e:90:7c:ae: ... 9c:e9:8a:8b:bc:c7:71:de:2d ...
The exponent is the default value 65537. (More on that here.)
The large numbers are displayed in hexadecimal with colons separating pairs of hex digits. If you remove the colons and concatenate everything together, you can verify that the number called modulus is indeed the product of the numbers called prime1 and prime2. I verified this for the output above using a little Python code:
modulus = 0xa7b839...c5 prime1 = 0xdc8c27...f9 prime2 = 0xc2ae20...2d assert(prime1*prime2 == modulus)Related postsThe post Generating and inspecting an RSA private key first appeared on John D. Cook.