I recently decided I would open up a new code repository using Git version control, in this case BitBucket, instead of Github due to their free private repository offering. While historically, on a Windows OS at least, I have used Git Extensions for my Git repos, and PuTTYgen/Pageant to create/handle my RSA private/public keypairs.
With PuTTY you typically keep the .PPK file (The file you get when you hit the "your private key" button) and give the public key, or public ssh-rsa key string, to your host/SSH server. However, recently upon doing the same old song and dance with PuTTYgen, I thought to myself that there must be a more secure solution to access my code in a repository, or at least store the private key. After all, the majority of people out there just whip up PuTTYgen, make an unencrypted (un-passphrased) private key using the same old basic RSA cipher.
Unencrypted vs Encrypted and the RSA Private Key
Traditionally, from what I've seen anyway, when you "generate" your RSA keypair, your private key is typically either the unencrypted kind (without passphrase) or the encrypted kind (with a passphrase). An unencrypted key is just something "you have", but an encrypted key is something you both "know" and "have", therefore if someone obtains your private key, they typically cannot "use it" without your passphrase. When you generate one of these keys using a program such as PuTTYgen, you are presented with a good amount of options and outputs (including the aforementioned/pictured ssh-rsa "public key for pasting into OpenSSH", and a "key fingerprint"), but no matter what, you are presented with an "RSA Private Key" that looks like this:
-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: AES-128-CBC,CFD2D34EB83EF37F04F1153232B29723 KpaXu0pAeRKVritszk1TJwOTYQLaQq+B1Qw6KXdAqyb3qOlJdqsVAHxqXpCzJ25h PPLLVFivWdkWnJYiurZ4WKWB8zs4tBx5IrkD/S31Z6PzqRyn6FPhVCB8UUVGxqFf .... blah blah blah.... VCsv5s23CiTW+gmeBvNC/E91QXl8L8Yl43tUBvzqEdvkjcKUkuteyN/XhH41MJgz -----END RSA PRIVATE KEY-----
The biggest issue with this however is it's based on the fact that the passphrase you use is merely MD5'd with part of your Initialization Vector (IV). The "CFD2D34..." part to the right of the "AES-128-CBC" cipher (the IV) is basically just concatenated with your passphrase (code for "glued together", in this case "appended to") and then MD5'd. MD5 is old. It doesn't take a rocket scientist to realize that it has been severely compromised and many people have known it for years. It can be easily bruteforced as well, in fact, I used to do this as a Freshman in High School.
For the sake of Modernness use PKCS#8
I'm not a security expert, but PKCS#8 is supposedly thee standard for storing a private key (I may be wrong, but PuTTY surely isn't right). In a nut shell, it allows for a better cipher & hash of your choosing, thus more passphrase protection as it's harder to bruteforce. Anyway, I am writing this blog post because it took me a little while to figure out how to get my better security for my private key while still being able to use Bitbucket, Git Extensions and sadly Windows.
How to make a custom PKCS#8 Private Key with a Public SSH Key for Git
Note: These are instructions for Windows, but you can do this way easier in Linux.
Getting Ready to run some Commands
- Download/Install Git
- Download/Install Git Extensions
- Open Git Extensions, go to the Tools => Settings menu. Under Git Extensions => SSH, under "Specify which ssh client to use", select "Other ssh client".
- Download OpenSSH for Windows and install the client (you don't need the server component).
- Open a command line in the C:\Program Files (x86)\Git\bin directory (example is a 64-bit Win 7 machine)
- Git comes with openssl.exe in it's bin folder already, so add it to your Windows path, or just download OpenSSL separately. Either way just get it so you can type "OpenSSL" and "SSH" on command line without getting any "'OpenSSL' is not recognized as internal or external command" errors.
- In Windows 7+, open up an explorer Window and browse to your default SSH user folder (that was created when OpenSSH installed), Example: C:\Users\Admin\.ssh\ You might see some keys that may have already been generated, if so, ignore/delete them.
Create your Key Pairs
You can do this many ways, but I've found a couple that are useful depending on your needs.
-
The OpenSSH to PKCS#8 Method
Note: "ssh-keygen" is an OpenSSH command.ssh-keygen -t rsa -N 'password123' -f C:\Users\Admin\.ssh\key openssl pkcs8 -topk8 -v2 des3 -in C:\Users\Admin\.ssh\key -out C:\Users\Admin\.ssh\key.p8
The first command creates a private & public keypair with password "password123" and outputs 2 files "key" and "key.pub" (your private and public ssh-rsa key respectively). The second command takes the previously generated private "key" file and encrypts it to a PKCS#8 (key.p8) file using DES3 encryption.
-
The OpenSSL to PKCS#8 Method (More useful)
openssl genrsa -aes256 -out C:\Users\Admin\.ssh\key 4096 openssl pkcs8 -topk8 -v2 des3 -in C:\Users\Admin\.ssh\key -out C:\Users\Admin\.ssh\key.p8 ssh-keygen -y -f C:\Users\Admin\.ssh\key > C:\Users\Admin\.ssh\key.pub
In this case, the first command only generates a private key like above, but it is using AES-256 4096. The second command converts the private key to PKCS#8 (just like above). Note: The "ssh-keygen"/3rd command in this second example will error, if you use clipboard input for your passphrase, instead of typing it manually. Additionally, the 2nd command asks for the passphrase 3 times. This is to re-encrypt the key, so you can use either the same passphrase 3 times, or 2 different passphrases and it should still work. Unfortunately this isn't pure OpenSSL because you still need a ssh-rsa key string, so that's what the last command does (unless of course your host accepts straight up public keys).
If you noticed, it doesn't matter if you convert your private key, the public key stays the same. I purposely used as much prompting for passwords as possible in the previous commands (preference), but you can use input files and such if you wish. When all is said and done, you should have a private "key.p8" file and a public "key.pub" file. Once you have your .p8 file, be sure to relocate/destroy your original "key" file (no .p8 [or .pub] extension) somewhere else (it defeats the purpose if you keep it). You should also notice that your PKCS#8 file should have a header that starts with "-----BEGIN ENCRYPTED PRIVATE KEY-----" instead of "-----BEGIN RSA PRIVATE KEY-----", and will lack the "Proc-Type" and "DEK-Info" headers from the original private key. This is because all of the data is serialized with the headers prior to encryption.
Setting up SSH for Bitbucket (or another Git host)
To connect to a service like Bitbucket with SSH for example, you would then go into your repo settings and select "Deployment keys", click "Add Key" and paste the contents of the "key.pub" file into the textarea (careful to omit spacs/newlines that are added via word wrap from any advanced text editor).
After that, create a file in the .ssh folder called "config". Write in:
Host bitbucket.org IdentityFile ~/.ssh/key.p8
Be sure to include a space before "IdentityFile".
Then go into GitBash, type in "eval `ssh-agent`" and then "ssh-add C:/path/to/key.p8", you should then be prompted for your passphrase and you should be authorized. If not, recheck your steps. In Git Extensions, attempt to clone/commit to your repository.