When softwares such as ecryptfs use AES, it asks for a user password (such as "password123").
The AES algorithm by itself does not call for a user password. So where does the "password123" get thrown into the math?
I'm working to make a C function that encrypts some data using a password. I know the typical way of doing it with OpenSSL and an aes key, but I don't know how to get a user password integrated.
You need to use a key derivation function (KDF). Password-Based Key Derivation Function 2 (PBKDF2) is the current most common approach.
OpenSSL probably exposes PBKDF2, it typically takes in a password and an iteration count (modern systems should use something like 100000 or higher... crank up the number until it takes about 0.3 seconds), and an output length. It may also take a hash function, something in the SHA-2 family (SHA256, SHA384, SHA512) would be a good modern choice.
Related
(Not to be confused with the DES algorithm subkey generation)
(edit: more examples)
Explanation of problem:
I'm doing this as part of a school assignment where I'm required to recode parts of OpenSSL in C, specifically those pertaining to PKI cryptosystems. So far I've recoded from scratch the core DES algorithm with ecb, cbc, 3des-ecb, and 3des-cbc modes of operation. Other parts of the project include MD5 and SHA256. This portion of the project focuses on RSA key generation, manipulation and usage.
Part of RSA key manipulation includes encrypting a given key with a passphrase.
(not with the pure key + initial vector alone like I've done before with DES)
This requires converting the user-input passphrase to a DES key (and optional additional IV as needed), and then using that to encrypt a RSA key. I know the general term for the function I'm looking for is PBKDF, or Password-Based Key Derivation Function. However, I have not been able (through searching the man pages of OpenSSL or google) to find what exact function (or functions) are used in OpenSSL for key derivation.
Demonstration of DES key generation encrypting RSA keys:
Running the following command with no passphrase generate an unencrypted RSA key example_plain_key.
ssh-keygen -t rsa -f example_plain_key
Then running the following commands will encrypt example_plain_key with the des cipher in ecb mode. Each command outputs the encrypted version to a new file so it doesn't change the original. Use the same passphrase for both commands (password, for example).
openssl rsa -DES-ECB -in id_rsa -out id_rsa_1
openssl rsa -DES-ECB -in id_rsa -out id_rsa_2
You can use head id_rsa and head id_rsa_1 to see how encrypting a key changes the header. If you compare the two new keys with
diff id_rsa_1 id_rsa_2
they will be identical in the header and formatting, but the key itself will be encrypted differently, even though the same passphrase is used. The difference is because the key generation (I believe) generates a new random salt every time it is ran. I would assume the hashing algorithm and the number of iterations would be the same. Also, unlike /etc/shadow on unix machines, the salt doesn't appear to be stored alongside the key (or at least I don't know how to read it).
Demonstration of DES key generation from password:
A more DES-specific example is:
openssl des -P
Running the above command any number of times with the same password will always result in a different key and iv, probably because the salt is different.
My findings, and deducted assumptions:
Searching "how are rsa keys encrypted?" brings up a lot of results on using RSA keys to encrypt. (sometimes I expect too much from Google's nlp)
Searching "how are DES keys generated from passphrase?" brings up a lot of results on how to generate the 16 round des subkeys.
I've skimmed the source of OpenSSL with no luck. I'll do an exhaustive search if absolutely necessary, but the code isn't the most readable or searchable.
php prototype
perl man page
A link I thought would be more helpful than it was
(Note: I don't have an account with OpenSSL but don't think it'd be required to view)
The most helpful findings led me to believe an example prototype of what I'm looking for would look something like this:
#include <unistd.h>
#include <stdio.h>
#include <pwd.h>
// #include <something_else_maybe.h>
int main(void)
{
int num_iterations = 1000;
char *salt;
char *passphrase;
char *key;
passphrase = getpass("Password: ");
salt = get_some_random_bytes(8); // assumed arbitrary length
// the function in question
key = example_pbkdf(md5_function, num_iterations, salt, 8, passphrase, strlen(passphrase));
printf("Key (in hexadecimal or otherwise) is: %s\n", key);
free(key);
free(passphrase);
free(salt);
return (0);
}
Things I am specifically looking for:
(Knowing where to look for these answers would be more valuable than the answers themselves, but all help is appreciated. I do need the header/source/prototype/etc in C though.)
The function (if it exists) that operates like the one demonstrated above. It doesn't have to be a perfect match, I'm more concerned about what it does rather than the exact prototyping or usage.
Alternatively, (if it doesn't exist) the "recipe" or series of operations that could be summarized as "the algorithm" I'm looking for.
DES key generation. (though including multiple ciphers, say, AES, is awesome too)
How the salt is stored in an ecrypted RSA key, if it is (and if it isn't, how to recover it). I know the IV is stored in the header of a key encrypted with a cipher in CBC.
I need to calculate fingerprint for a public key in C. Is there a way to do this in C platform?
I am using openSSL library also. Is there any call in openSSL to get this done?
Fingerprints are usually associated with asymmetric encryption keys (e.g, RSA, DSA, ECC) — they are not typically used for symmetric keys, such as AES, and as such there is no standard way of doing this. You can certainly take the hash of an AES key using the algorithm of your choice, though.
I'm trying to write a simple file enc/decryption within a larger project.
I'd like to avoid libgpgme because of license issues. The openPGP standard is to complex for the project timeframe i have.
I'd like to do my encryption stuff with openssl.
Now i've implemented the following:
encryption (pseude code):
RAND_bytes(aes_key)
RAND_bytes(aes_salt)
EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), (const unsigned char *)aes_salt, aes_key, sizeof(aes_key), 5, key, iv);
then i aes256 my data
EVP_EncryptInit_ex(&e_ctx, EVP_aes_256_cbc(), NULL, key, iv);
then i encrypt the key and iv with RSA
RSA_public_encrypt(flen, (unsigned char *)key, encryptedKey, rsa, RSA_PKCS1_PADDING );
RSA_public_encrypt(flen, (unsigned char *)iv, encryptedIV, rsa, RSA_PKCS1_PADDING );
then i save the 128bit key and iv at the "top" of my file (256Bytes header).
decryption:
-> read the first 256bytes (split into key and iv)
-> decrypt the key and iv with the local RSA Private Key (of course the RSA Private Key IS NOT in the file)
-> use the key and iv to decrypt the data
Am i kind of safe with that code?
Since this is a new format, you should use OAEP padding. Just change RSA_PKCS1_PADDING to RSA_PKCS1_OAEP_PADDING. You actually don't need to encrypt the IV (it can't hurt as far as I can tell, and it might help).
Otherwise, this method should be fine so long as RSA_size(rsa)==16. Of course, the private key must not be knowable by anyone who should not be able to decrypt the file.
Encryption is a topic where things are easy to make "work" - but hard to make secure. When in doubt (and doubly so when not in doubt), pick a widely recognized standard and implement precisely to spec. The idea of encrypting the key with a public-private algorithm, then packing the IV in as well is sound in theory, but I'm not sure what the implications of encrypting the IV as well are, and what happens if the attacker starts flipping bits in the encrypted data? Etc. It looks sound, but again, I would strongly recommend simply implementing a published spec precisely.
I would recommend just implementing S/MIME, using a binary transfer encoding. S/MIME is recognized as being a secure specification, there are libraries implementing all the hard parts, and most importantly, you can test your implementation against other implementations to make sure you're not out of spec.
Since you are using the OpenSSL envelope-encryption functions anyway, you should just directly use the EVP_SealInit() / EVP_SealUpdate() / EVP_SealFinal() functions. These functions take care of generating the symmetric key and IV, encrypting the data with the symmetric key and encrypting the symmetric key with the recipient(s) RSA key(s).
Once thing that you are not taking care of is authenticity. Under CBC mode it is possible for an attacker to make certain predictable changes to the plaintext, even if they can't read it. To detect this, you should either calculate a HMAC over the encrypted message (using a seperate symmetric key to that used for encryption), or sign the encrypted message (eg. with EVP_SignInit() / EVP_SignUpdate() / EVP_SignFinal()).
Some observations:
The EVP_BytesToKey function is meant to create a key and initialization vector from a password and salt, not from random data. It will work, but you could also simply use the random bytes directly as key and initialization vector. (Make sure you are using a secure PRNG, I'm not sure what RAND_bytes actually does.)
The initialization vector does not need to be secret, CBC mode should be secure with a non-encrypted IV. (This does not hurt, though.)
The RSA encryption looks good (but you might want to use another padding, as David said).
As Serdalis said, you should also protect your file against modifications. Any keyed MAC will do (most common are HMAC build on a key and a hash function). Apply the MAC after encryption.
I'm working on a project that involves writing low-level C software for a hardware implementation. We are wanting to implement a new feature for our devices that our users can unlock when they purchase an associated license key.
The desired implementation steps are simple. The user calls us up, they request the feature and sends us a payment. Next, we email them a product key which they input into their hardware to unlock the feature.
Our hardware is not connected to the internet. Therefore, an algorithm must be implemented in such a way that these keys can be generated from both the server and from within the device. Seeds for the keys can be derived from the hardware serial number, which is available in both locations.
I need a simple algorithm that can take sequential numbers and generate unique, non-sequential keys of 16-20 alphanumeric characters.
UPDATE
SHA-1 looks to be the best way to go. However, what I am seeing from sample output of SHA-1 keys is that they are pretty long (40 chars). Would I obtain sufficient results if I took the 40 char key and, say, truncated all but the last 16 characters?
You could just concatenate the serial number of the device, the feature name/code and some secret salt and hash the result with SHA1 (or another secure hashing algorithm). The device compares the given hash to the hash generated for each feature, and if it finds a match it enables the feature.
By the way, to keep the character count down I'd suggest to use base64 as encoding after the hashing pass.
SHA-1 looks to be the best way to go. However, what I am seeing from sample output of SHA-1 keys is that they are pretty long (40 chars). Would I obtain sufficient results if I took the 40 char result and, say, truncated all but the last 16 characters?
Generally it's not a good idea to truncate hashes, they are designed to exploit all the length of the output to provide good security and resistance to collisions. Still, you could cut down the character count using base64 instead of hexadecimal characters, it would go from 40 characters to 27.
Hex: a94a8fe5ccb19ba61c4c0873d391e987982fbbd3
Base64: qUqP5cyxm6YcTAhz05Hph5gvu9M
---edit---
Actually, #Nick Johnson claims with convincing arguments that hashes can be truncated without big security implications (obviously increasing chances of collisions of two times for each bit you are dropping).
You should also use an HMAC instead of naively prepending or appending the key to the hash. Per Wikipedia:
The design of the HMAC specification was motivated by the existence of
attacks on more trivial mechanisms for combining a key with a hash
function. For example, one might assume the same security that HMAC
provides could be achieved with MAC = H(key ∥ message). However, this
method suffers from a serious flaw: with most hash functions, it is
easy to append data to the message without knowing the key and obtain
another valid MAC. The alternative, appending the key using MAC =
H(message ∥ key), suffers from the problem that an attacker who can
find a collision in the (unkeyed) hash function has a collision in the
MAC. Using MAC = H(key ∥ message ∥ key) is better, however various
security papers have suggested vulnerabilities with this approach,
even when two different keys are used.
For more details on the security implications of both this and length truncation, see sections 5 and 6 of RFC2104.
One option is to use a hash as Matteo describes.
Another is to use a block cipher (e.g. AES). Just pick a random nonce and invoke the cipher in counter mode using your serial numbers as the counter.
Of course, this will make the keys invertible, which may or may not be a desirable property.
You can use an Xorshift random number generator to generate a unique 64-bit key, and then encode that key using whatever scheme you want. If you use base-64, the key is 11 characters long. If you use hex encoding, the key would be 16 characters long.
The Xorshift RNG is basically just a bit mixer, and there are versions that have a guaranteed period of 2^64, meaning that it's guaranteed to generate a unique value for every input.
The other option is to use a linear feedback shift register, which also will generate a unique number for each different input.
I'm using OpenSSL in a program that decrypts a text file and then re-encrypts it with new text and a new encryption key every time the program starts. I'd like to safely store the key between instances of the program running. Is there an easy/decently safe way of doing this?
If you don't expect hard core attacks on the machine that the application is installed on, you can always hardcode inside your application another encryption key that you would use in order to safely save the previous session AES key in the file system before you close the app and to retrieve it back when you start the app. You could improve a bit the security if:
you don't store the harcoded key into a single string, but instead in several strings that you then concatenate in a function
you save the file in a relatively "unknown"/unpopular location like the Isolated Storage, or Windows\Temp instead of the application folder
you use an asimetric key algorithm (makes cracking harder.. but in this case.. just a little bit)
you put other stuff (bogus) in the file not just the key
If your program is not in a safe area (if its binary code can be inspected to find any key it would contain or any algorithm it would define) there is no simple way:
You could obfuscate your key programmatically and store it in a file, but in that case, breaking your obfuscation algorithm would be sufficient to find the key. So this would reduce the strengh of the encryption to that algorithm, actually. Not a good way to go.
You could also encrypt the key (called A here) itself, using a static key (called B) embedded in your program, but in that case, you would lose the interest of changing the key A every time. This because finding the key B embedded in your program would be sufficient to find any encrypted key A saved to the disk. This would not be satisfactory either.
Considering more complex solutions requires knowing your context a bit more (where can the attack come from, what is the lifecycle of the file, etc). But before going that far... is it needed to go that far? By this I mean: is your program at risk of cracking attempts? And should it be cracked, it that criticial? If not crackable or not critical, the second option above should be sufficient.
If your target host has a TPM chip, you can take advantage of it. OpenSSL can be configured to use TPM, with the help of trousers project