(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.
Related
What I am searching for is a decrypt function to the crypt(3) function. Reading the manual they only refer me to see login(1), passwd(1), encrypt(3), getpass(3), passwd(5), but as far as I am aware, non of them can be used to decrypt the string.
I wrote together a small program to show my point, the function I am looking for is the somefunctogetbackplaintext(...)
#define _XOPEN_SOURCE
#include <unistd.h>
#include <string.h>
#include <stdio.h>
int
main(int argc, char *argv[])
{
char *cryptated = crypt(argv[1], "aa"); // Password and salt
if(strcmp("somepassword", somefunctogetbackplaintext(argv[1], cryptated, "aa"))) //Plain text, cryptated string, salt
{
printf("Success!\n");
}
else
{
printf("Not a success!\n");
}
return 0;
}
crypt does not encrypt passwords (so there is no way to decrypt them). Instead it hashes a given password, producing a string that is impossible to reverse to the original password (because the hash function loses information in the process). The most practical way to attack crypt and recover passwords from their hashes is probably some sort of dictionary attack.
However, none of that is necessary to check whether a given password is correct:
const char *password_and_salt = ...; // e.g. from getpwent or a database
const char *input = argv[1];
if (strcmp(crypt(input, password_and_salt), password_and_salt) == 0) {
printf("your password is correct\n");
}
In other words, you pass the user input to crypt and check whether it matches the known result of an earlier crypt. If so, the passwords match.
Here is a summary excerpt from this article distinguishing between the concepts of encryption and Hashing:
Passwords remain the primary means for online authentication and must
be protected when stored on a server. Encryption is an option, but it
has an inherent weakness in this application because the server
authenticating the password must have the key to decrypt it. An
attacker who steals a file of encrypted passwords might also steal the
key.
Hashing is a better option, especially with the judicious use of salt,
according to mathematician Andrew Regenscheid and computer scientist
John Kelsey of the National Institute of Standards and Technology’s
Computer Security Division.
Encryption is a two-way function; what is encrypted can be decrypted
with the proper key. Hashing, however, is a one-way function that
scrambles plain text to produce a unique message digest. With a
properly designed algorithm, there is no way to reverse the hashing
process to reveal the original password. An attacker who steals a file
of hashed passwords must then guess the password.
(emphasis mine)
Also (from comments) this link plainly states: crypt is the library function which is used to compute a password hash...
As wikipedia article about crypt states:
Excerpt 1:
crypt is the library function which is used to compute a password hash that can be used to store user account passwords while keeping them relatively secure (a passwd file).
Excerpt 2:
This is technically not encryption since the data (all bits zero) is not being kept secret; it's widely known to all in advance. However, one of the properties of DES is that it's very resistant to key recovery even in the face of known plaintext situations. It is theoretically possible that two different passwords could result in exactly the same hash. Thus the password is never "decrypted": it is merely used to compute a result, and the matching results are presumed to be proof that the passwords were "the same."
So that is the answer to question: "the password is never "decrypted""
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 want to send large data encrypted with RSA through sockets. I use openssl and c.
Because RSA decryption is quite slow I use the common and straight forward way to encrypt the data with AES first, and afterwards I encrypt the used AES password with RSA. Then I send both, the AES encrypted data and the RSA encrypted password, through the socket and do the encryption the other way around.
I do the AES encryption with:
EVP_CIPHER_CTX en;
unsigned char password[65];
int i, x = 0;
unsigned char key[32], iv[32];
unsigned char *ciphertext;
i = dataLength + AES_BLOCK_SIZE -1;
ciphertext = (unsigned char *)malloc(i);
EVP_CIPHER_CTX_init(&en);
EVP_EncryptInit_ex(&en, EVP_aes_256_cbc(), NULL, key, iv);
EVP_EncryptUpdate(&en, ciphertext, &i, (unsigned char*)data, dataLength);
EVP_EncryptFinal_ex(&en, ciphertext+i, &x);
But how do I create the key and the iv securely? Right now I Use the following function:
EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, password, 64, 9, key, iv);
My question is:
How do I create "password" correctly?
Because if I use rand() or something equal my attempt was completely useless because anybody who is able to get behind the "randomness" used for the "password" generation is able to decrypt the data anyway without caring about the RSA encryption of the "password".
Is there a function for secure passwordgeneration in openssl? Or is EVP_BytesToKey() just the wrong way to do what I want to do?
The default RAND_bytes method is fortunately seeded per thread, and by default uses the random number generator available from the operating system. The OpenSSL documentation seems to be out of date where Windows is involved, but you can find more information on this by looking at the answer of the venerable Thomas Pornin on security.stackoverflow.com.
EVP_BytesToKey is used to generate keys from passwords. EVP_BytesToKey is a key derivation function (KDF) that is specific to OpenSSL. OpenSSL also implements PBKDF2 which is the NIST approved method of password based key derivation function (PBKDF). But as you want a random key, not a derived key, none of those functions apply.
So please use rand(). If possible, try to check how the function is seeded for your specific platform.
Also note OpenSSL 1.1.0c changed the digest algorithm used in some internal components. Formerly, MD5 was used, and 1.1.0 switched to SHA256. Be careful the change is not affecting you in both EVP_BytesToKey and commands like openssl enc.
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 am using RSA algorithm for shared key encryption/decryption.I am using open ssl libraries and c language.RSA_size() returns 256bytes.the key(data to enrypt) size is more than 256bytes but less than 500 bytes.The RSA keysize used for encryption is 1024.keypair is generated using openssl library.
If data to encrypt is less than or equals to 245 bytes the encryption works fine(because of padding).Otherwise i have to break the data(not sure it is ok as iam trying to exchange shared key)Is there any other way to increase RSA_size.my code doesn't call RAND_seed()(not sure what argment to pass) before calling rsa_public_encrypt. Any help is appreciated.
You can either break your data into chunks, or use the "seal"/"open" OpenSSL functions.
Essentially what they do is generate a random set of keys, encrypt the keys using the public key and then use those keys to encrypt whatever you want. That way you're not limited to specific sizes and decryption is not too slow (you only decrypt the random keys using RSA, the rest is done using symmetric encryption so it's a lot faster).
I suggest you have a look at EVP_SealInit and EVP_OpenInit.