OpenSSL Hacks
July 1st, 2006 by Anthony J. Stieber in
OpenSSL is a powerful Secure Sockets Layer cryptographic library. Apache uses it for HTTPS encryption, and OpenSSH uses it for SSH encryption. But, you don't have to use it as a library. It's also a multipurpose, cross-platform crypto tool.
Here's a little background on OpenSSL. Before OpenSSL, there was ssleay, an SSL implementation written by Eric A. Young. It was successively improved and eventually became OpenSSL, similar to how NCSA HTTPd became the Apache Web server. Today, OpenSSL supports dozens of cryptographic algorithms and protocols with hundreds of options.
OpenSSL has a lot of features. In addition to the SSL client and server features, OpenSSL also has:
US federal government NIST FIPS 140-2 Level 1 validation.
TLS, the next generation of SSL.
X.509 key and certificate generation.
X.509 certificate authority.
S/MIME encryption.
File encryption and hashing.
UNIX password hashes.
Nine different commercial cryptographic hardware devices.
Cryptographic performance testing.
Thirty-six commands.
Six message digest algorithms.
Nine cipher algorithms with four block modes (where applicable).
Multiple crypto protocols.
Although OpenSSL is complex, a lot of that complexity can be avoided. The remainder of this article concentrates on features that are easy to use, and in only a few lines of shell code.
This article uses the same section titles as in my earlier GnuPG article (“GnuPG Hacks”, Linux Journal, March 2006, page 52) to make it easier to compare OpenSSL and GnuPG.
First, let's confirm that OpenSSL is installed and in your path. Many Linux distributions, even some small distributions, include OpenSSL. Usually OpenSSL is located in /usr/bin/, like most bundled packages.
In all of the examples, the shell prompt is set to $.
First, type:
$ openssl version
Note that there are no leading dashes for the version option.
You should get something like this:
OpenSSL 0.9.7d 17 Mar 2004
The exact version number, date and other details may vary. At the time of this writing, the current version is OpenSSL 0.9.8a. The examples we're using should work for most versions of OpenSSL.
If you typed openssl with no command-line option, you'll get this:
OpenSSL>
If this happens, simply type quit or press Ctrl-C to exit safely. It's only the OpenSSL internal command-line prompt. It doesn't have command-line editing and has no explicit help function. But, it will type a list of commands if you type a command it doesn't know. It's better to avoid it for now.
Binary files typically are sent in e-mail using MIME. However, if your e-mail software doesn't support MIME, like most command-line e-mail, you're stuck with uuencode, or you can use OpenSSL's base64 encoding. Base64 is the same encoding used by the much more complicated MIME protocol, but it's not directly MIME-compatible.
To wrap a file in base64 text encoding, type:
$ openssl base64 < filename.bin > filename.txt
To unwrap a base64-encoded file, type:
$ openssl base64 -d < filename.txt > filename.bin
Note that OpenSSL doesn't care about the filename extension.
OpenSSL, unlike GnuPG or MIME, also can encode short strings, as follows:
$ echo "The Linux Journal" | openssl base64 VGhlIExpbnV4IEpvdXJuYWwK
Decoding is similar:
$ echo "VGhlIExpbnV4IEpvdXJuYWwK" | openssl base64 -d The Linux Journal
sum and cksum are the traditional UNIX checksum programs. They work fine, as long as as you don't need cross-platform compatibility or security, and you don't mind that occasionally two completely different files will have the same checksum value.
Although Linux systems often have md5sum installed, the MD5 algorithm suffers from a relatively new vulnerability and shouldn't be used anymore.
If it's installed, the more secure sha1sum should be used. Several different programs go by this name, however. Some versions can hash only one file at a time, some can't handle stdin or have some other deficiency. If you run into any of these problems or simply want consistent, known, good cross-platform software, consider OpenSSL.
The OpenSSL hash output format is a bit different from GnuPG, but numerically identical. OpenSSL format always identifies the algorithm used and also outputs a lowercase hexadecimal string with no whitespace. Some find this format easier to use.
Here are some examples:
$ openssl sha1 filename SHA1(filename)= e83a42b9bc8431a6645099be50b6341a35d3dceb $ openssl md5 filename MD5(filename)= 26e9855f8ad6a5906fea121283c729c4
As in my previous “GnuPG Hacks” article, the above examples use a file that contains the string: “The Linux Journal”. Note that there is no period in the string.
If you have a problem replicating these results, here is the ASCII-annotated hexadecimal representation of the file. Note the newline at the end automatically added by vi:
T h e L i n u x J o u r n a l \n 54 68 65 20 4c 69 6e 75 78 20 4a 6f 75 72 6e 61 6c 0a
OpenSSL, unlike GnuPG, doesn't have SHA-512, but OpenSSL does have MD2, MD4 and MDC2. These are older algorithms that are provided for backward compatibility. Like MD5, they shouldn't be used anymore.
Although not OpenSSL's strength, it also can encrypt files. The flexibility of OpenSSL makes it a bit more complicated than GnuPG.
OpenSSL has very few defaults, so more options have to be used. There are also many algorithms from which to choose. Some algorithms, like DES and RC4-40, are kept only for backward compatibility and shouldn't be used anymore. Strong algorithms you should use include bf, which is the Blowfish algorithm, and -aes-128-cbc, which is the US NIST Advanced Encryption Standard (AES) with 128-bit keys running in Cipher Block Chaining (CBC) mode.
Here is an example:
$ openssl enc -aes-128-cbc < filename > filename.aes-128-cbc enter aes-128-cbc encryption password: Verifying - enter aes-128-cbc encryption password:
As with GnuPG, OpenSSL asks for a passphrase twice, which will not echo to the screen.
Decryption is also a bit more complicated:
$ openssl enc -d -aes-128-cbc -in filename.aes-128-cbc > filename enter aes-128-cbc decryption password:
Note the -d in this example, which specifies decryption.
OpenSSL, unlike GnuPG, does not automatically detect the file type or even what algorithm, key length and mode were used to encrypt a file. You need to keep track of that yourself. In my example, I've put that information in the filename extension. OpenSSL won't manage the files and file extensions for you, you have to specify where you want the outgoing data written.
If you don't specify the correct algorithm, OpenSSL either may spew garbage or complain about a bad magic number. Either way, without the correct options, your data won't decrypt properly. To be fair, this is simply not something OpenSSL was designed to do, but it does work.
Before we go much further, we should discuss the importance of passphrases. In most cryptosystems, the passphrase is the secret that keeps the other secrets. It's usually the weakest point. So, creating strong passphrases is important, but it's also difficult, unless you have the right tools. Using OpenSSL, you can create a strong passphrase quickly.
A simple guide to passphrases is that longer is usually better, and eight characters is not long enough (Table 1). The goal is to make a secret that you can remember but that someone else won't know, can't guess or won't eventually stumble upon.
Table 1. Password and passphrase strengths compared with estimated time to crack. Note: time to crack is very rough. Your crackage may vary.
| Type | Bytes | Characters | Bits/Character | Total Bits | Time to Crack |
|---|---|---|---|---|---|
| Base64 [A-Za-z0-9+/=] | 6 | 8 | 6 | 48 | Minutes to hours |
| Base64 [A-Za-z0-9+/=] | 9 | 12 | 6 | 72 | Years |
| Base64 [A-Za-z0-9+/=] | 12 | 16 | 6 | 96 | Decades |
| Base64 [A-Za-z0-9+/=] | 15 | 20 | 6 | 120 | Uncrackable? |
| Diceware Passphrase | 8 words | 12.9 per word | 120 | Uncrackable? |
OpenSSL can create very strong random passphrases like this:
$ openssl rand 15 -base64 wGcwstkb8Er0g6w1+Dm+
If you run this example, your output will be different from the example, because the passphrase is randomly generated.
The first argument of 15 is the number of binary bytes to generate, and the second argument of -base64 specifies that those binary bytes should be encoded in base64 characters. For 15 bytes, the output always will be 20 characters, plus a newline character.
The base64 character set consists only of uppercase and lowercase letters A–Z, the numbers 1–9 and the three punctuation characters: plus, slash and equals. This is intentionally a limited character set, but more complexity in the character set is not necessarily better. Adding only one additional character makes up for the difference in security. For example, an eight-character fully printable ASCII password is about a strong as a nine-character base64 password.
Although not as quick as using OpenSSL rand, the Diceware passphrase generator produces strong and often easy-to-memorize passphrases. I highly recommend it.
Here's something that GnuPG can't do. OpenSSL has a built-in command for creating encrypted Linux passwords exactly like those made by /bin/passwd.
Skip this paragraph to avoid pedantic cryptography. Although commonly called encrypted, Linux passwords are actually hashed using either MD5 or the old UNIX password hash (based on the DES encryption algorithm). This allows Linux not to know your password even though it knows when you provide the correct password. When you set your password, Linux hashes your password and stores it in /etc/shadow. When you log in, Linux takes the password you provide and hashes it again, and then compares that hash to what's stored in /etc/shadow for your account. If they match, you provided the correct password and can log in. If they don't match, you don't know your password, and because only the hash was stored, the computer still doesn't know your password either.
Here's why making your own password hash is useful. Let's say you need a new password on another computer. Perhaps it's a new account or you forgot the old password and asked the system administrator to reset it for you. If you can talk to the sysadmin in person, this works well, but what if the sysadmin is somewhere else? Perhaps you've never even met your sysadmin. How do you communicate your new password? E-mail is not secure at all, and telephones are scarcely better. Postal mail takes days (and has other security problems). Fax machines, text messaging and most pagers aren't secure either.
It gets worse. Maybe you don't even trust that sysadmin. Sure, the sysadmin usually has root, but someone else knowing your password bypasses even root accountability. Maybe you want to use the same password on other computers, and you don't trust those sysadmins either.
So, do this instead:
$ openssl passwd -1 Password: Verifying - Password: $1$zmUy5lry$aG45DkcaJwM/GNlpBLTDy0
Enter your new password twice; it won't echo. If you have multiple accounts, run the above example multiple times. The output is the cryptographic hash of your password. The hash is randomly salted so that every time it's run, the output will be different, even if the password is the same.
In my example, the password hash is:
$1$zmUy5lry$aG45DkcaJwM/GNlpBLTDy0
Your password hash probably will be completely different, except for the initial $1$.
This password hash can now be e-mailed, faxed, text messaged or even spoken over the phone to a sysadmin to set as your password hash.
After the sysadmin receives your password hash, it can be entered into /etc/shadow manually or with chpasswd. The latter requires a temporary new file, call it newpassword, with your loginid and password hash like this:
LoginidHere:$1$ywrU2ttf$yjm9OXTIBnoKJLQK2Fw5c/
The file can contain multiple lines for other accounts too.
Then, the sysadmin runs this as root:
chpasswd --encrypted < newpassword
Now, the new password is set. It's a good idea to change your password once you log in, unless you use a really strong passphrase. This is because the password hash, once exposed, is subject to off-line brute-force attacks, unless the password is really long.
This method of resetting passwords can be quite secure. For example, using this technique, someone could take the password hash published above, create an account, then tell the person the loginid and hostname and that the password hash above was used. Only the person who originally created the password hash could know the password, even though the password hash was published in a magazine.
By the way, the password for that hash is 28 completely random base64 characters long, so it should be extremely difficult to crack. But please, don't create any accounts with that hash because the password is also published, it's:
HXzNnCTo8k44k8v7iz4ZkR/QWkM2
That password and hash were created like this:
$ openssl rand 21 -base64 HXzNnCTo8k44k8v7iz4ZkR/QWkM2 $ openssl passwd -1 HXzNnCTo8k44k8v7iz4ZkR/QWkM2
These examples use the MD5 password hashes now common on Linux systems. If you need to use the old UNIX password hash, simply leave off the -1. For example:
$ openssl passwd Password: Verifying - Password: xcx7DofWC0LpQ
The password for this last password hash example is: TheLinux.
The many algorithms that OpenSSL supports makes it well suited for cryptographic benchmarking. This is useful for comparing the relative performance of different cryptographic algorithms and different hardware architectures using a consistent code base. And, it has a built-in benchmarking command.
The openssl speed command, by default, runs through every single algorithm in every single supported mode and option, with several different sizes of data. The different sizes are important because of algorithm start-up overhead.
A complete speed run takes about six minutes, regardless of hardware performance, and produces 124 lines of performance data with 29 lines of summary.
However, note that cryptographic algorithm performance is extremely dependent on the specific implementation. For higher performance, OpenSSL has x86 assembly code for several algorithms. Other architectures, such as ia64, SPARC and x86-64, have much less assembly code, and most others have none. The assembly code is located in these OpenSSL source code directories: crypto/*/asm. Excerpts of the speed report for three different systems are shown in Tables 2 and 3.
Table 2. Hash and Block Cipher Performance (The numbers are in 1,000s of bytes per second using 1,024-byte blocks.)
| AMD K6-2 300MHz, Linux 2.6.12, OpenSSL 0.9.7g | AMD Athlon 1.333GHz, Linux 2.4.27, OpenSSL 0.9.7d | PowerMac G5 1.6GHz, Darwin Kernel Version 8.0.0, OpenSSL 0.9.7b | |
|---|---|---|---|
| md5 | 26,733.93k | 169,207.13k | 76,921.71k |
| sha1 | 12,665.41k | 113,973.25k | 76,187.82k |
| blowfish cbc | 9,663.40k | 56,940.54k | 44,433.14k |
| aes-128 cbc | 5,134.78k | 31,355.90k | 54,987.78k |
Table 3. Public Key Crypto Performance
| sign/s | verify/s | ||
|---|---|---|---|
| rsa 1024 bits | 30.8 | 563.1 | AMD K6-2 300MHz, Linux 2.6.12, OpenSSL 0.9.7g |
| dsa 1024 bits | 61.6 | 50.7 | AMD K6-2 300MHz, Linux 2.6.12, OpenSSL 0.9.7g |
| rsa 1024 bits | 239.9 | 4,514.6 | AMD Athlon 1.333 GHz, Linux 2.4.27, OpenSSL 0.9.7d |
| dsa 1024 bits | 498.2 | 410.6 | AMD Athlon 1.333 GHz, Linux 2.4.27, OpenSSL 0.9.7d |
| rsa 1024 bits | 148.8 | 2,739.1 | PowerMac G5 1.6 GHz, Darwin Kernel Version 8.0.0, OpenSSL 0.9.7b |
| dsa 1024 bits | 289.5 | 234.6 | PowerMac G5 1.6 GHz, Darwin Kernel Version 8.0.0, OpenSSL 0.9.7b |
This is only a sample of what OpenSSL offers at the command line.
Some documentation is available at the OpenSSL Web site under the Documents and Related sections. There are also several mailing lists available under the Support section.
OpenSSL is written in and for C/C++, but it has been adapted to other programming languages, including Ruby. In addition, the FIPS 140-2 Level 1 validation in March 2006 makes OpenSSL a new contender in the enterprise and government cryptography markets.
Resources for this article: /article/9020.
Special Magazine Offer -- Free Gift with Subscription
Receive a free digital copy of Linux Journal's System Administration Special Edition as well as instant online access to current and past issues. CLICK HERE for offer
Linux Journal: delivering readers the advice and inspiration they need to get the most out of their Linux systems since 1994.
Subscribe now!
The Latest
Newsletter
Tech Tip Videos
- Nov-19-09
- Nov-04-09
Recently Popular
From the Magazine
December 2009, #188
If last month's Infrastrucuture issue was too "big" for you then try on this month's Embedded issue. Find out how to use Player for programming mobile robots, build a humidity controller for your root cellar, find out how to reduce the boot time of your embedded system, and if you're new to embedded systems find out the basics that go into one. You can also read about the Beagle Board, the Mesh Potato and a spate of other interestingly named items. And along with our regular columns don't miss our new monthly column: Economy Size Geek.
Delicious
Digg
StumbleUpon
Reddit
Facebook








In relation to the password
On September 2nd, 2007 IainB (not verified) says:
In relation to the password hash, surely the server needs to know the salt too? When I run the example I don't get the salt returned, so how can the hash be used?? Can the salt be derived from the hash somehow, and if so, doesn't knowledge of the salt make the hash much, much weaker?
I'm sure I've missed something obvious!
As far as I know, the salt
On March 8th, 2009 aurir_ (not verified) says:
As far as I know, the salt is stored between two dollar signs. So it's part of the hash. At least for the MD5 (openssl passwd -1).
MD5 passwd hash
On February 10th, 2007 BernieD (not verified) says:
I need a cc or gcc source file that I can compile on an HP running HPUX 11. I want to compile it into an existing process that currently generates and hashes 8 digit passwords using DES i.e., the old crypt(). I nust now increase that password from 8 positions to 15 for security purposes. I'd guess that a perl script would do also as long as it had the proper hooks to the MD5 hash.
I will really appreciate any help on this item.
RE:
On August 4th, 2006 Anonymous (not verified) says:
Great Article Anthony!
Very interesting and informational.
Can you expand a little on where you say:
"...run the above example multiple times. The output is the cryptographic hash of your password. The hash is randomly salted so that every time it's run, the output will be different, even if the password is the same."
Why will the output be different?
Thanks!
-John
salt
On December 13th, 2006 Wu Yongzheng (not verified) says:
Basically, salt is a random string appended to your password. So instead of hash(password), we do hash(password | salt). The server keeps both salt and hash value. The purpose of salt is to prevent pre-calculated table attack.
Ref: http://en.wikipedia.org/wiki/Salt_%28cryptography%29
Page is rendered too wide
On June 2nd, 2006 rhkramer says:
The lines on this page are too wide, I have to scroll horizontally to read each line, hence I haven't read the article.
The problem seems to be Table 2, and specifically the header lines, but Table 3 may also be wide on some screens.
I'm sure someone can find a number of creative ways to solve the problem.
Randy Kramer
Page is rendered too wide
On June 4th, 2006 Keith Daniels (not verified) says:
In most browsers, those capable of handling cascading style sheets (CSS) that table displays with a horizontal scroll bar at the bottom and does not extend the page width.
What browser are you using and what version?
Webmaster
Linux Journal
I forgot to ask
On June 4th, 2006 Keith Daniels says:
Have you changed the settings in your browser so you use a default or customized style sheet for it? This is common with Opera.
Webmaster
Linux Journal
Width problem
On October 7th, 2006 Allan Morris (not verified) says:
The width problem on this page as commented by others is still there. Using Konqueror 3.5.4 on Kubuntu with stylesheet set as default. Browser as-is passes the acid style test 100%. The problem is with your site.
Sorry.
Allan Morris.
Width problem
On October 7th, 2006 Keith Daniels says:
There were two problems here. Though I made the page quit showing so wide, the problems still exist.
Problem #1 Konqueror will not obey the CSS rule (overflow: auto;) for a table which would make a horizontal scroll bar appear only underneath the over sized table and the screen would not display wide. All other browsers I tested do this.
Problem #2 Konqueror obeyed a CSS rule for table headers (th{white-space: nowrap;}) that none of the other browsers paid any attention to. I killed the white-space rule and the page no longer over extends your screen (or at least not as much, there is still a point where the table headers will not continue to wrap). If the other browsers had obeyed this rule I would have found this problem much earlier.
Webmaster
Post new comment