- The Key and IV are derived from the password you specify, using an OpenSSL-specific algorithm that the OpenSSL team is not proud of. They keep it around for backward compatibility's sake, but they recommend that you use better password-based key derivation functions, such as PKCS's PBKDF2.
OpenSSL's bespoke key derivation algorithm is in the function EVP_BytesToKey(3).
Key:
-K key
the actual key to use: this must be represented as a string comprised only of hex digits.
IV:
In cryptography, an initialization vector (IV) or starting variable
(SV)[1] is a fixed-size input to a cryptographic primitive that is
typically required to be random or pseudorandom.
So the IV is additional input used to encrypt the file. It is not the key (I guess it's just terminology).
2 A salt is an additional (prefix) to the key you specify. (see Wikipedia. It makes it impossible to use rainbow tables or precalculated hash tables on your key. The salt is usually stored unencrypted.
3 The output will be binary and will quite likely contain non-printable characters. Your terminal emulator will try to render those byte values as printable characters in its default character encoding and typeface, but they will probably look like "garbage text" and not be safe for copy/paste, FTP or email.
4 To decrypt an encrypted text, you need the Key and IV. If you don't have one or both of those, and the ones you're missing were derived from the Password, then if you have the Password, you can re-derive they missing Key and/or IV from the Password. You don't need the Salt, because you already have it; it's pre-pended to the beginning of the encrypted text. The Salt isn't really a secret, it's just a way to foil pre-computed hash tables and rainbow tables.
5 As defined in EVP_BytesToKey(3), if you use a password of "1" and --nosalt
, the first 16 Bytes of your Key will be:
md5( D_0 || password || salt)
(note that in this context, ||
means concatenation, not logical or
)
which is equivalent to
md5 ( `null` || "1" || `null`)
which is equivalent to
md5("1")
Which turns out to be
0xc4ca4238a0b923820dcc509a6f75849b
This value is what the man page calls D_1
.
The remaining needed bytes of the Key and IV are generated like this:
md5( D_1 || password || salt)
which is equivalent to
md5( 0xC4CA4238A0B923820DCC509A6F75849B || "1" || `null` )
which is equivalent to
md5( 0xC4CA4238A0B923820DCC509A6F75849B31 )
(note that the ASCII "1" becomes 0x31 concatenated at the end of the D_1
value)
which turns out to be:
0x7976c7161415c830816dd4068a1d9a52
which is what that man page calls D_2.
The Key only needs 8 more bytes than D_1
already proved, so it takes the first 8 bytes of D_2 and becomes:
Key: C4CA4238A0B923820DCC509A6F75849B7976c7161415c830
The IV only needs 8 bytes, and since there are 8 unused bytes from D_2, they become the IV:
IV: 816dd4068a1d9a52
Here's a command-line to generate D_1, the first 16 bytes of the Key (given your example of password "1" and --nosalt
):
echo -n "1" | openssl md5
Here's a command-line to generate D_2, the remaining 8 bytes of the Key, plus all 8 bytes of the IV (again, given your example inputs):
echo -n "$(echo -n "1" | openssl md5 -binary)1" | md5
This works by taking the output of D_1 (making sure to keep it in binary rather than translating it into ASCII-encoded hex digits), appending "1" (0x31) to it, and taking the md5
of that.