Passwords or pass phrases are basically a human equivalent of keys used by algorithms on computers. However, because of that passwords also carry a lot of burden that make them unsuitable as keys:
- they are generally much less random than they symmetric key counterparts, because humans are quite incapable as random number generators;
- they may be dynamically sized, which makes them unsuitable for many cryptographic algorithms;
- they often use a specific set of characters (al alphabet) of their own;
- they can be converted to bytes in many ways, if just because there are many character encodings;
- the chances of reuse are rather high, so the leaking one password may influence security of many systems.
Generally cryptographers use a PBKDF or password hash to create a statically sized, random byte array from a password. This byte array can then be used as a key, or it can be used to authenticate a person on e.g. a webservice.
These PBKDF's strengthen or stretch the security of the password by a certain work factor. This work factor is usually represented by an iteration count or by a value that is converted into an iteration count (bcrypt uses a work factor which is exponential).
Furthermore, they require a salt to avoid that the same password will create the same hash, even on multiple systems. Because of this rainbow table attacks can be avoided.
Other configuration parameters such as deliberate use of more memory to avoid attacks by specialized hardware or GPU based systems may also be present. See e.g. scrypt. Another common configuration parameter is to allow multiple threads to calculate a single password; it doesn't seem used much.
One configuration parameter that is often missing because it is simply implied is the character encoding. Quite often initial operation to convert characters to bytes is the cause of interoperability issues. Some PBKDF's are also limited to the amount of input bytes (e.g. some bcrypt implementations limit to 72 bits, which can be problem for passphrases).
OpenSSL uses its own PBKDF called
EVP_BytesToKey. It uses a rather insecure iteration count of 1, which means that no real strengthening is performed. Furthermore, it also uses a salt, which is stored in the positions 8..15 of the ciphertext, preceded by a magic value
"Salted__" in ASCII (take a look at the head of your ciphertext!). You may have to decode the base 64 first though (or compare against
U2FsdGVkX1 at the start, most of
The salt is generated during encryption, and with the iteration count it is able to derive a key, which is used to encrypt your plaintext. During decryption the salt is read so it is able to derive the same key - but only if you give it the correct password of course. Once the key is calculated again it can decrypt the ciphertext.
Newer versions have an option to use PBKDF2 instead. This algorithm doesn't disallow hackers to use specialized hardware, but it is at least more secure than the original
EVP_BytesToKey with an iteration count of 1.
Neither the password or key is stored with the ciphertext. The password is supplied by the user, the key is derived from that password and the salt.
Note that the ciphertext allows an attacker to perform a so called offline attack, where all computing resources can be used on the ciphertext to try and get to the password by guessing it (using dictionary attacks and such). This is different from web services that can e.g. include a timeout between tries or only allow a certain number of guesses - as long as the password hash is kept secret.
A much more secure way of encrypting files is to use a trusted public key of the receiver. Then the receiver can use their private key to decrypt the ciphertext. Commonly this is used in a hybrid cryptosystem that uses both asymmetric cryptography and symmetric cryptography. However, it does require that the public key can be trusted, so you need a Public Key Infrastructure of some kind to trust the keys. This is what e.g. PGP uses for file encryption.
Often a password may still be used, but that's just to decrypt the private key, and the private key is usually kept on the system of the user, so it isn't available to adversaries.