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.
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 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 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.
Good Afternoon all,
I am working over rsa encryption and decryption, for more security i am also using padding in cipher text, for different input (amit) , i am getting different length output like-
plain text- amit
cipher text-10001123A234A987A765A
My problem is- For big plain text ,my algo generate large size cipher text, and i thought,
it is wastage of resources to keep long string in database ,
Is there any way with the help of that i can compact cipher and convert real cipher when i will require?
In order for the algorithm to be encryption and not just hashing, it must be reversible. To be reversible, the output must contain as much information as the input, and so is unlikely to be significantly shorter.
You may compress the data before encryption. There's not a lot else you can do unless you're willing to give up the ability to recover your original text from the ciphertext.
There are a couple of possibilities:
Change your encryption scheme there are schemes where the size is same as the input size
Compress your data before you encrypt, this will be effective only if you have a large block of text to encrypt and then there's the additional overhead of decrypting too.
This doesn't apply to RSA specifically, but: any secure cipher will give output close to indistinguishable from a random bit pattern. A random bit pattern has, per definition, maximum information theoretic entropy, since for each bit, both 0 and 1 are equally likely.
Now, you want a lossless compression scheme, since you need to be able to decompress to the exact data you originally compressed. An optimal compression scheme will maximize the entropy of it's output. However, we know that the output of our cipher already has maximum entropy, so we can't possibly increase the entropy.
And thus, trying to compress encrypted data is useless.
Note: Depending on your encryption method, compression might be possible, for example, when using a block cipher in EBC mode. RSA is a completely different beast altogether though, and, well, compressing won't do anything (except quite possibly make your final output bigger).
[Edit] Also, the length of your RSA ciphertext will be in the order of log n. With n your public modulus. This is the reason that, especially for small plaintexts, public key crypto is extremely 'wasteful'. You normally employ RSA to setup a (smaller, e.g. 128-bit) symmetric key between two parties and then encrypt your data with a symmetric key algorithm such as AES. AES has a block size of 128 bits, so if you do straightforward encryption of your data, the maximum 'overhead' you incur will be length(message) mod 128 bits.
erm ... you wrote in a comment here that you apply RSA encryption to all single characters:
i am using rsa- it perform over
numbers to convert amit in cipher text
first i do a->97 m->109 i->105..and
then apply rsa over 97 ,109 ... then i
get different integers for 109, 105 or
... i joined that all as a string...
a good advice: don't do that since you will lose the security of RSA
if you use RSA in this way, your scheme becomes a substitution-cypher (with only one substitution alphabet) ... given a reasonably long cypher-text or a reasonable number of cypher-texts, this scheme can be broken by analyzing the frequency of cypher-text-chars
see RSAES-OAEP for a padding scheme to apply to your plaintext before encryption