Encrypting a plain text file in C - c

I am currently writing a linux application in C that reads from a configuration file. This configuration file contains some data that I would like to encrypt so it is not plain text. I have spent hours researching this and have not found a viable solution. Since the application will need to read from the configuration I will need to be able to encrypt it and decrypt it on the fly. So far from research I really like openSSL crypto library. I know from the command line you can do:
openssl enc -aes-256-cbc -salt -in file.txt -out file.enc
If anyone can provide an example of how I can do this in C, it would be most appreciated.

You should have a look at the O'Reilly-Book. There are a couple of examples on how to encrypt things. Unfortunately the most are for Network-Encryption.
I found an example in the book, but didnt test it:
#include <openssl/evp.h>
int main(int argc, char *argv[])
{
EVP_CIPHER_CTX ctx;
char key[EVP_MAX_KEY_LENGTH];
char iv[EVP_MAX_IV_LENGTH];
char *ct, *out;
char final[EVP_MAX_BLOCK_LENGTH];
char str[] = "123456789abcdef";
int i;
if (!seed_prng())
{
printf("Fatal Error! Unable to seed the PRNG!\n");
abort();
}
select_random_key(key, EVP_MAX_KEY_LENGTH);
select_random_iv(iv, EVP_MAX_IV_LENGTH);
EVP_EncryptInit(&ctx, EVP_bf_cbc(), key, iv);
ct = encrypt_example(&ctx, str, strlen(str), &i);
printf("Ciphertext is %d bytes.\n", i);
EVP_DecryptInit(&ctx, EVP_bf_cbc(), key, iv);
out = decrypt_example(&ctx, ct, 8);
printf("Decrypted: >>%s<<\n", out);
out = decrypt_example(&ctx, ct + 8, 8);
printf("Decrypted: >>%s<<\n", out);
if (!EVP_DecryptFinal(&ctx, final, &i))
{
printf("Padding incorrect.\n");
abort();
}
final[i] = 0;
printf("Decrypted: >>%s<<\n", final);
}
char *encrypt_example(EVP_CIPHER_CTX *ctx, char *data, int inl, int *rb)
{
char *ret;
int i, tmp, ol;
ol = 0;
ret = (char *)malloc(inl + EVP_CIPHER_CTX_block_size(ctx));
for (i = 0; i < inl / 100; i++)
{
EVP_EncryptUpdate(ctx, &ret[ol], &tmp, &data[ol], 100);
ol += tmp;
}
if (inl % 100)
{
EVP_EncryptUpdate(ctx, &ret[ol], &tmp, &data[ol], inl%100);
ol += tmp;
}
EVP_EncryptFinal(ctx, &ret[ol], &tmp);
*rb = ol + tmp;
return ret;
}
char *decrypt_example(EVP_CIPHER_CTX *ctx, char *ct, int inl)
{
/* We're going to null-terminate the plaintext under the assumption it's
* non-null terminated ASCII text. The null can be ignored otherwise.
*/
char *pt = (char *)malloc(inl + EVP_CIPHER_CTX_block_size(ctx) + 1);
int ol;
EVP_DecryptUpdate(ctx, pt, &ol, ct, inl);
if (!ol) /* there's no block to decrypt */
{
free(pt);
return NULL;
}
pt[ol] = 0;
return pt;
}
Hope this will help you.

Check this answer and check this article.
You can replace EVP_bf_cbc() with EVP_aes_128_cbc() EVP_aes_192_cbc() or EVP_aes_256_cbc() depending on what you need.

You need the SSL development packages. (libssl-dev in Ubuntu). Depending on how you implement it, you will also need libcrypto-dev.

I'm not a huge O'Reilly fan, but I found this book to be very helpful when starting this type of thing for the first time.

Why not do your own? Read enough bytes from dev/random (your key) and XOR the configuration file with it. To decrypt, XOR again with the same key. This is simple,fast,and secure. No complicated libraries needed.

Related

Libgcrypt - extract RSA encrypted data from a gcry_sexp_t object

I'm trying to extract the encrypted RSA data from a gcry_sexp_t object (which I assume is an MPI), so I could store the encrypted data as an encrypted file (without the other gcrypt metadata in the sexp object).
I've tried using gcry_sexp_sprint, which serialized the whole sexp object and which kind of works, but I assume that is not the intended way for storing RSA encrypted bytes on the disk. I've also tried extracting data using gcry_sexp_nth_buffer and gcry_sexp_nth_mpi, both of which just return the string enc-val.
This code is the relevant part:
gcry_sexp_t ciph;
err = gcry_pk_encrypt(&ciph, msgSexp, this->publicKey);
if(err){
throw std::runtime_error("gcry_pk_encrypt error: " + std::string(gcry_strerror(err)));
}
After this, I have a gcry_sexp_t object holding all of the relevant data, of which I would like to extract the encrypted data.
Thank you!
EDIT: I ended up calling gcry_sexp_nth two times to traverse the nested S expression object and then using gcry_sexp_nth_data to get the raw encrypted data. I'm sure there's a better way, though.
Libgcrypt API to deal with SExpression is very powerful. You can get data from the expression easily. Here is a sample code which:
Generate key pair
Encrypt a random data
Extract cipher text value
#include <stdio.h>
#include <gcrypt.h>
#include <string.h>
static void die(const char *format, ...) {
va_list arg_ptr;
va_start(arg_ptr, format);
vfprintf(stderr, format, arg_ptr);
va_end(arg_ptr);
if (*format && format[strlen(format) - 1] != '\n') {
putc('\n', stderr);
}
exit(1);
}
static void show_sexp(const char *prefix, gcry_sexp_t a) {
char *buf;
size_t size;
if (prefix)
fputs(prefix, stderr);
size = gcry_sexp_sprint(a, GCRYSEXP_FMT_ADVANCED, NULL, 0);
buf = gcry_xmalloc(size);
gcry_sexp_sprint(a, GCRYSEXP_FMT_ADVANCED, buf, size);
fprintf(stderr, "%.*s", (int) size, buf);
gcry_free(buf);
}
int main() {
gcry_sexp_t key_spec, key, pub_key, sec_key;
int rc;
size_t len;
gcry_sexp_t cipher, l;
gcry_sexp_t plain;
gcry_mpi_t x;
const int nbits_data = 512;
//-------------------------------------------------------------------
// Generate Key
//-------------------------------------------------------------------
rc = gcry_sexp_new(&key_spec, "(genkey (rsa (nbits 4:2048)))", 0, 1);
if (rc) {
die("error creating S-expression: %s\n", gcry_strerror(rc));
}
//>> Generate key
rc = gcry_pk_genkey(&key, key_spec);
gcry_sexp_release(key_spec);
if (rc) {
die("error generating RSA key: %s\n", gcry_strerror(rc));
}
show_sexp("generated RSA key:\n", key);
//>> Extract parts
pub_key = gcry_sexp_find_token(key, "public-key", 0);
if (!pub_key) {
die("public part missing in key\n");
}
sec_key = gcry_sexp_find_token(key, "private-key", 0);
if (!sec_key) {
die("private part missing in key\n");
}
//-------------------------------------------------------------------
// Encrypt Data
//-------------------------------------------------------------------
//>> Create plain text.
x = gcry_mpi_new(nbits_data);
gcry_mpi_randomize(x, nbits_data, GCRY_WEAK_RANDOM);
rc = gcry_sexp_build(&plain, NULL, "(data (flags raw) (value %m))", x);
if (rc) {
die("converting data for encryption failed: %s\n", gcry_strerror(rc));
}
//>> Encrypt data.
rc = gcry_pk_encrypt(&cipher, plain, pub_key);
if (rc) {
die("encryption failed: %s\n", gcry_strerror(rc));
}
//-------------------------------------------------------------------
// Extract value
//-------------------------------------------------------------------
show_sexp("Encrypted data:\n", cipher);
l = gcry_sexp_find_token(cipher, "a", 0);
const char *data = gcry_sexp_nth_data(l, 1, &len);
for (int i = 0; i < len; i++) {
printf("%02x", (unsigned char) data[i]);
}
printf("\n");
return 0;
}
And this is the output:
generated RSA key:
(key-data
(public-key
(rsa
(n #00D43DB15B8AB929675C0196F8750451F2814F62FBF36219008051F99C82EB89B138FAFCBA51DB24D1DAADF6706016C268F59C793E91F05630376E58DCFAE728EEA1D26714244334643BB3A285D0860E9800ECBD5B85B11F4962F438A6C6D465851A991426A4AFF819D1B0D2DA28C016B80613B28070EAEC54A8CDF8EB5D04F03E8F925E384B75D3CEF326CF03901AD053925DFA08B0E8A38E8F6D1C4E14299312FB38791D23EDDFB9B57CAD596BFF09C4EEE0AF85CFC5A228BA5330A8C6F17B233FF8EB351B35C2FD26C3C723B9E4E89A3728D33D5D6C4D35931A0463FBF3FA1D056B4A5B1274BBB82B345130C2DE0FBCC4C258ED2EE3AA28A149A20A6BA0B2C7#)
(e #010001#)
)
)
(private-key
(rsa
(n #00D43DB15B8AB929675C0196F8750451F2814F62FBF36219008051F99C82EB89B138FAFCBA51DB24D1DAADF6706016C268F59C793E91F05630376E58DCFAE728EEA1D26714244334643BB3A285D0860E9800ECBD5B85B11F4962F438A6C6D465851A991426A4AFF819D1B0D2DA28C016B80613B28070EAEC54A8CDF8EB5D04F03E8F925E384B75D3CEF326CF03901AD053925DFA08B0E8A38E8F6D1C4E14299312FB38791D23EDDFB9B57CAD596BFF09C4EEE0AF85CFC5A228BA5330A8C6F17B233FF8EB351B35C2FD26C3C723B9E4E89A3728D33D5D6C4D35931A0463FBF3FA1D056B4A5B1274BBB82B345130C2DE0FBCC4C258ED2EE3AA28A149A20A6BA0B2C7#)
(e #010001#)
(d #29943875AD949EB6E00073BA12FA98AF4083F3E95601E6D201518DEC0A7DE848AED804C0DF9E65F532B917E965F9AF766E7F8C052504076E84BD7A6D383E26F7B0FE0E3194F511837D6AB0B1346BBEDA2A7C3690827D739AA5E7205E13DFB24FC4292F186EF5064ED094AA8A10A7A90BBE2D07B03FEED603B3DA3E24A5E17CCAF93E8CF54DE7C690FA08C4D57691FB47F637C283B6B8F2752F1FDDF303E5DA3D32ECCE9EE36F78AE83C74C0F875A11E3F907F7DA2197138BC22709123FAC72FD65937E730B99372BDC5A94958A288B67D448534CBB11CCEDA4D5DDB83040FA373932520A0268EE3CCD9BCD3D1040E7DD177E452DBD0CA91442AA39E29A2614F9#)
(p #00DA039BF562531FA1E2098E0D642D38DB35FCE5CC7D56EE397A2BBAE61DE0777341024D914183C6B9EF83FAE962BC4EC4DA3036B643FD1F6E8EF20E489AF9FA997F860F80DA672B85216DAAEFA91059ED340EB8A7411A2DCDCCE23DB0AB414B8BD2FFB516E23B8AB0D95717DE5A253EC96A7B2FD1BFDA3B001CA590200FEF1F6B#)
(q #00F93893CE49EB488250AA6D1F568CA14D247EBBEA2FC47D70A5BBF211543DF06F3B5BA51F4119481371B6433D6C1150F14EB19C5C44B7335F4FF3BE3C2FBDC8E17920CEC5D194A71E9F6B0715D7CD6867AB6D0F384A02CDECBBE111BB1276DAD40B872268E3381F3032C44D8B01BC80ACDC3C19D04735D1007202085E345C1D15#)
(u #00AFC622BC85AB68634EE4EBE0AAFA9DD612A11E7E09657AC937FFD4642622BD63BF825ACD419F273D86E77D74AAA6FBB8A28C633D58C6DDE1F9C5655B5AF8E412CDDA43DCA008EE084AB45D9C8DB454601D7CBB4739692FA91FD910A8A67D5041E339FBD2920875439F5D97C574E21A9DE8C779ADDF67686A940221E4518B6AE4#)
)
)
)
Encrypted data:
(enc-val
(rsa
(a #4CAC81402948B4E0A0FEFCECF89C389D711AAD158D3B6A927FA7D6D276C6BD7AAACA2CDEBB88A2430A0948AD9CFB2192D6521B90C291EDC122D6E7422915FCB083C987204CADCC6BF956B296C33A1CADBF5972921FE58454A6076E29B368195739FDAD3D02D612147E413E7E01E6185CA1784DA2F31874DE9C3DFB31DEE4764BA066BF208C0F362EB25C780001D5AD285DBD41450C735AFBFEE8CF35A178A007865629DC5A3ED50257E473DF73DC02422924E1541393824B91336D30F3989CA2FE8E4BA463673F1BF83EC0D95E958FD2B757699F805B342D52729232568228E01632607821CC9F116580496C228524FD4E3147CF6F6E9456FBBAD1FFD1889F0D#)
)
)
4cac81402948b4e0a0fefcecf89c389d711aad158d3b6a927fa7d6d276c6bd7aaaca2cdebb88a2430a0948ad9cfb2192d6521b90c291edc122d6e7422915fcb083c987204cadcc6bf956b296c33a1cadbf5972921fe58454a6076e29b368195739fdad3d02d612147e413e7e01e6185ca1784da2f31874de9c3dfb31dee4764ba066bf208c0f362eb25c780001d5ad285dbd41450c735afbfee8cf35a178a007865629dc5a3ed50257e473df73dc02422924e1541393824b91336d30f3989ca2fe8e4ba463673f1bf83ec0d95e958fd2b757699f805b342d52729232568228e01632607821cc9f116580496c228524fd4e3147cf6f6e9456fbbad1ffd1889f0d

How can I add IV (initialization vector) to AES-256 ECB Encryption to create AES-256 CBC mode?

I have the following code working for AES-256 ECB encryption using a simple byte-oriented AES-256 library I found here.
Main:
#define DUMP(s, i, buf, sz) {printf(s); \
for (i = 0; i < (sz);i++) \
printf("%02x ", buf[i]); \
printf("\n");}
int main (int argc, char *argv[])
{
aes256_context ctx;
uint8_t key[32] = "39P8TXDMBCYF4C1NI1CDFJ1WL6P5TTKZ";
uint8_t buf[16] = "KUC7EWG6M2D1WW8F";
uint8_t i;
DUMP("txt: ", i, buf, sizeof(buf));
DUMP("key: ", i, key, sizeof(key));
printf("---\n");
aes256_init(&ctx, key);
aes256_encrypt_ecb(&ctx, buf);
DUMP("enc: ", i, buf, sizeof(buf));
aes256_init(&ctx, key);
aes256_decrypt_ecb(&ctx, buf);
DUMP("dec: ", i, buf, sizeof(buf));
aes256_done(&ctx);
return 0;
}
Encryption function:
void aes256_encrypt_ecb(aes256_context *ctx, uint8_t *buf)
{
uint8_t i, rcon;
aes_addRoundKey_cpy(buf, ctx->enckey, ctx->key);
for(i = 1, rcon = 1; i < 14; ++i)
{
aes_subBytes(buf);
aes_shiftRows(buf);
aes_mixColumns(buf);
if( i & 1 ) aes_addRoundKey( buf, &ctx->key[16]);
else aes_expandEncKey(ctx->key, &rcon), aes_addRoundKey(buf, ctx->key);
}
aes_subBytes(buf);
aes_shiftRows(buf);
aes_expandEncKey(ctx->key, &rcon);
aes_addRoundKey(buf, ctx->key);
} /* aes256_encrypt */
I want to add an IV to this program to create AES-256 CBC mode. From what I understand, IV implementation is as follows:
XOR the first block with the IV.
XOR all following blocks with the cipher text of the previous block.
My question is what does the logic look like? How do I implement that into my code?
The logic and explanations can be found in a few places. For example in: ECB vs CBC or Block cipher mode of operation.
CBC = Cipher Block Chaining is a way of connecting blocks together.
What is does is instead of just processing each block separately, every block will be XOR’ed with the encrypted previous block. This effectively means that every block depends on the output of the previous block.
Each block is XORed with the ciphertext of the previous block as it is explained by diagrams in the quoted articles.
In practice once one block is encrypted by ECB encription:
Cipher((state_t*)buf, ctx->RoundKey);
as in
void AES_ECB_encrypt(struct AES_ctx *ctx,const uint8_t* buf)
{
// The next function call encrypts the PlainText with the Key using AES algorithm.
Cipher((state_t*)buf, ctx->RoundKey);
}
CBC is achieved by XOR with IV on the block, ECB on the same block and moving along the blocks in the buffer.
Example of XOR with IV:
static void XorWithIv(uint8_t* buf, uint8_t* Iv)
{
uint8_t i;
for (i = 0; i < AES_BLOCKLEN; ++i) // The block in AES is always 128bit no matter the key size
{
buf[i] ^= Iv[i];
}
}
Example of CBC with the use of XOR with IV and ECB :
void AES_CBC_encrypt_buffer(struct AES_ctx *ctx,uint8_t* buf, uint32_t length)
{
uintptr_t i;
uint8_t *Iv = ctx->Iv;
for (i = 0; i < length; i += AES_BLOCKLEN)
{
XorWithIv(buf, Iv);
Cipher((state_t*)buf, ctx->RoundKey);
Iv = buf;
buf += AES_BLOCKLEN;
//printf("Step %d - %d", i/16, i);
}
/* store Iv in ctx for next call */
memcpy(ctx->Iv, Iv, AES_BLOCKLEN);
}
The above implementation comes from tiny-AES and you may want to study it and adapt it to your needs. I hope it helps.

encrypt with mcrypt in ecb mode in c

I'm trying to encrypt a long char array with libmcrypt in c. I have a problem after I call my encrypt funktion more then 5 times. I can't see the mistake, but I'm getting strange output. If I have a 64 character plaintext it encrypts the first 32 characters and then for the last 32 I get twice the same 16 characters. I hope u get what I meen. Here my code:
char *Encrypt( char *key, char *message, int buff_len){
unsigned char *Res;
MCRYPT mfd;
char *IV;
int i, blocks, key_size=16, block_size;
mfd = mcrypt_module_open(MCRYPT_RIJNDAEL_128, NULL, "ecb", NULL);
block_size = mcrypt_enc_get_block_size(mfd);
blocks = ceil((double)buff_len/block_size);
mcrypt_generic_init(mfd, key, key_size, IV);
Res = calloc(1, (blocks *block_size)+1);
strncpy(Res, message, buff_len);
//memset(message,'\0',blocks *block_size);
mcrypt_generic(mfd,Res,(blocks *block_size));
//printf("the encrypted in function(Encrypt) %s len %d\n",Res, strlen(Res));
mcrypt_generic_deinit(mfd);
mcrypt_module_close(mfd);
return (Res);
}
and in the main I call:
char seed[] = "thesecretmessage which I really want to check if if works", key1[]="abcdefghijklmnop";
int buff_len = strlen(seed), i;
char *encrypted = Encrypt(key1, seed, buff_len), *encrypted_pr=Encrypt(key1, encrypted, buff_len);
printf("the encrypted %s, %d\n", encrypted, strlen(encrypted));
printf("the encrypted_pr %s, %d\n", encrypted_pr, strlen(encrypted_pr));
for(i=0;i<15;i++){
memcpy(encrypted2, Encrypt(key1, encrypted2, buff_len),64);
printf("the encrypted_pr[%d] %s\n",i, encrypted_pr);
}
I'm really getting crazy on this. If I have a plaintext that's just 16 Bytes it works perfectly. Thanks for the help!

OpenSSL RSA: Unable to encrypt/decrypt messages longer than 16 bytes

I'm working on a simple program that uses OpenSSL to do basic RSA encryption and decryption. It is working fine for small messages (<16 bytes), but fails for anything over that. I understand that a limitation of public key cryptography is that you cannot encrypt anything longer than the key size. In my case, I'm using a 1024bit key, so I should have 128bytes to work with (maybe slightly less due to padding), correct? If so, that's not what I'm experiencing.
Here's the output from my program with 15 bytes:
Generating RSA keypair...done.
Message to encrypt: 0123456789ABCDE
16 bytes encrypted
Decrypted message: 0123456789ABCDE
And with 16 bytes:
Generating RSA keypair...done.
Message to encrypt: 0123456789ABCDEF
16 bytes encrypted
140153837057696:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:evp_enc.c:467:
Decrypted message: (null)
It seems that no matter what, only a total of 16 bytes are encrypted.
My encryption function (updated with fix):
unsigned char* rsa_seal(EVP_PKEY *pub_key, unsigned char *msg, size_t **enc_msg_len, unsigned char **sym_key, int *sym_key_len, unsigned char **iv) {
size_t msg_len = strlen((char*)msg);
unsigned char *encrypt = malloc(EVP_PKEY_size(pub_key));
EVP_CIPHER_CTX *ctx = malloc(sizeof(EVP_CIPHER_CTX));
EVP_CIPHER_CTX_init(ctx);
*sym_key = malloc(EVP_PKEY_size(pub_key));
*iv = malloc(EVP_MAX_IV_LENGTH);
**enc_msg_len = 0;
if(!EVP_SealInit(ctx, EVP_aes_128_cbc(), sym_key, sym_key_len, *iv, &pub_key, 1)) {
ERR_print_errors_fp(stderr);
encrypt = NULL;
goto return_free;
}
if(!EVP_SealUpdate(ctx, encrypt, (int*)*enc_msg_len, msg, (int)msg_len)) {
ERR_print_errors_fp(stderr);
encrypt = NULL;
goto return_free;
}
if(!EVP_SealFinal(ctx, encrypt, (int*)*enc_msg_len)) {
ERR_print_errors_fp(stderr);
encrypt = NULL;
goto return_free;
}
return_free:
EVP_CIPHER_CTX_cleanup(ctx);
free(ctx);
ctx = NULL;
return encrypt;
}
The corresponding decryption function (updated with fix):
char* rsa_open(EVP_PKEY *pri_key, unsigned char *enc_msg, size_t *enc_msg_len, unsigned char *sym_key, int sym_key_len, unsigned char *iv) {
size_t dec_len = 0;
unsigned char *decrypt = malloc((*enc_msg_len) + EVP_MAX_IV_LENGTH);
if(decrypt == NULL) return NULL;
EVP_CIPHER_CTX *ctx = malloc(sizeof(EVP_CIPHER_CTX));
EVP_CIPHER_CTX_init(ctx);
if(!EVP_OpenInit(ctx, EVP_aes_128_cbc(), sym_key, sym_key_len, iv, pri_key)) {
ERR_print_errors_fp(stderr);
decrypt = NULL;
goto return_free;
}
if(!EVP_OpenUpdate(ctx, decrypt, (int*)&dec_len, enc_msg, (int)*enc_msg_len)) {
ERR_print_errors_fp(stderr);
decrypt = NULL;
goto return_free;
}
if(!EVP_OpenFinal(ctx, decrypt, (int*)&dec_len)) {
ERR_print_errors_fp(stderr);
decrypt = NULL;
goto return_free;
}
decrypt[dec_len] = '\0';
return_free:
EVP_CIPHER_CTX_cleanup(ctx);
free(ctx);
ctx = NULL;
return (char*)decrypt;
}
The key generation function:
int rsa_init(EVP_PKEY **rsa_keypair) {
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
if(!EVP_PKEY_keygen_init(ctx)) {
ERR_print_errors_fp(stderr);
return -1;
}
if(!EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, KEY_LENGTH)) {
ERR_print_errors_fp(stderr);
return -1;
}
if(!EVP_PKEY_keygen(ctx, rsa_keypair)) {
ERR_print_errors_fp(stderr);
return -1;
}
EVP_PKEY_CTX_free(ctx);
return 0;
}
And finally, my main:
int main() {
EVP_PKEY *rsa_keypair = NULL; // RSA keypair
char msg[BUFFER]; // Message to encrypt
unsigned char *encrypt = NULL; // Encrypted message
char *decrypt = NULL; // Decrypted message
// Generate key pair
printf("Generating RSA keypair...");
if(rsa_init(&rsa_keypair) == -1) {
fprintf(stderr, "\nError generating RSA keypair.\n");
exit(1);
}
printf("done.\n");
// Get the message to encrypt
printf("Message to encrypt: ");
fgets(msg, BUFFER-1, stdin);
msg[strlen(msg)-1] = '\0';
// Load error strings in anticipation of error
ERR_load_crypto_strings();
// Encrypt the message
size_t *encrypt_len = malloc(sizeof(size_t));
unsigned char *sym_key = NULL;
unsigned char *iv = NULL;
int sym_key_len;
encrypt = rsa_seal(rsa_keypair, (unsigned char*)msg, &encrypt_len, &sym_key, &sym_key_len, &iv);
printf("%d bytes encrypted\n", (int)*encrypt_len);
// Decrypt it
decrypt = rsa_open(rsa_keypair, (unsigned char*)encrypt, (size_t*)encrypt_len, sym_key, sym_key_len, iv);
printf("Decrypted message: %s\n", decrypt);
free(encrypt);
free(decrypt);
free(encrypt_len);
free(sym_key);
free(iv);
EVP_PKEY_free(rsa_keypair);
return 0;
}
Any help is greatly appreciated! Thank you.
EDIT: As pointed out by math below, it seems that the answer to my mistake was hiding in the OpenSSL here: https://www.openssl.org/docs/crypto/EVP_EncryptInit.html#
This is because you do not properly handle out and outl parameters in EVP_SealUpdate(), EVP_SealFinal(), EVP_OpenUpdate() and EVP_OpenFinal().
Each EVP_XxxxUpdate() and EVP_XxxxFinal() call will contribute to the output buffer. So, you are required to keep track of the seal/open process by summing each outl returned and providing the expected buffer each time (start of buffer + already handled bytes).
unsigned char* rsa_seal(...)
{
...
**enc_msg_len = 0;
EVP_SealUpdate(ctx, encrypt + **enc_msg_len, &outl, msg, (int)msg_len);
**enc_msg_len += outl;
EVP_SealFinal(ctx, encrypt + **enc_msg_len, &outl);
**enc_msg_len += outl;
...
}
char* rsa_open(...)
{
...
dec_len = 0;
EVP_OpenUpdate(ctx, decrypt + dec_len, &outl, enc_msg, (int)*enc_msg_len);
dec_len += outl;
EVP_OpenFinal(ctx, decrypt + dec_len, &outl);
dec_len += outl;
...
}
The program was working with 15-bytes buffer because in that case, the EVP_XxxxUpdate() call is returning 0 in outl (not enough data to seal/open a block), hiding the problem in your code logic.
Note: The data is not directly encrypted using the RSA key but using a generated symetric key (AES-128 in your case). This is why the block size is 16 bytes.

Many doubts about decrypt an image file in c

Firstly, i'm not very familiarized with C, i come from Java, C#, C++... and possibly i inherited defects from this languages in order to realize this practice, well i have the follows question, here is my code:
#include <stdio.h>
#include <stdlib.h>
void decrypt(unsigned long* v, unsigned long* k);
const int MAX = 32;
const long delta = 0x9e3779b9;
long sum=0xC6EF3720;
int main() {
FILE *fp;
FILE *destino;
unsigned long v[2];
unsigned long k[4] = { 128, 129, 130, 131 };
unsigned long tam=0;
char* buffer;
char* aux[sizeof(unsigned long)];
int i;
if ((fp = fopen("image.png", "rb")) == NULL) {
printf ("Error! \n ");
return 0;
}
else {
fread(&aux,sizeof(unsigned long),1,fp);
memcpy(&tam,&aux,sizeof(unsigned long));
buffer = (char*)malloc(tam);
//fread(&buffer,1,tam,fp);
char *buffer2[28568];
fread(&buffer2,1,28568,fp);
/*for(i = 0;i < tam;++i) {
printf("%c", ((char *)buffer2)[i]);
}*/
for(i=4;i<tam;i+=8) {
memcpy(&v,&buffer2[i],8);
decrypt(&v,&k);
}
if ((result= fopen("image2.png", "rb")) == NULL) {
printf ("Error! \n ");
return 0;
}
else {
fwrite(v,sizeof(unsigned long)*2,1,result);
fclose (result);
fclose(fp);
}
}
return 0;
}
void decrypt(unsigned long* v, unsigned long* k) {
int i=0;
while(i<MAX) {
v[1] = v[1] -((4 << v[0])+(k[2]^v[0])+(sum^(5 >> v[0]))+k[3]);
v[0] = v[0] -((4 << v[1])+(k[0]^v[1])+(sum^(5 >> v[1]))+k[1]);
sum = sum-delta;
i++;
}
}
Where tam is the size of my binary file (image in this case) where i store first 4 bytes (unsigned long) where is located the size in my png file (28568)
When i create my char* buffer i have to assign dynamically with malloc but when i make a new fread from my file i get a "No source available for "msvrct!memcpy() at 0xrandom_memory_address" from Eclipse when i debug, well, i comment this line and i try to make it manually set a new buffer2 with 28568 as size of my array, apparently works, making a iteration of buffer2 prints ascii characters values but when i call decrypt for make the decryption of my image, the final result is stored in v array which i have to copy in a new file, i tried to search how to make a empty image png in C but i didn't find anything, so i created a copy of my encrypt image calling it "image2.png" but i suppose this not the "clean solution" for that, because for the other hand is not working at all.
For more explanation about this exercise just say that the decrypt funcion work with blocks of 8 bytes (64 bits) that through a key (array k) make a series of operation where they store in v array itself, crossing through the loop 8 in 8 and retrieve the value of buffer in v in each one, after the loop execution we have the result in v and only left to copy in a new file where finally show up the image decrypt.
It's a very complex practice for all of one newbies in C, it's driving my crazy trying to figure out what i doing wrong.
I hope anyone can see what i'm not able to for now.
I think you are having problems with the declarations of the buffers. I think the correct should be:
FILE *fp;
FILE *destino;
unsigned long v[2];
unsigned long k[4] = { 128, 129, 130, 131 };
unsigned long tam=0;
char* buffer;
char aux[sizeof(unsigned long)]; // without the "*"
int i;
if ((fp = fopen("image.png", "rb")) == NULL) {
printf ("Error! \n ");
return 0;
}
else {
fread(aux,sizeof(unsigned long),1,fp);
memcpy(&tam,aux,sizeof(unsigned long));
buffer = (char*)malloc(tam);
//fread(buffer,1,tam,fp); // without the "&" in this case
char buffer2[28568]; // without the "*"
fread(buffer2,1,28568,fp); // or fread(buffer,1,tam,fp);
/*for(i = 0;i < tam;++i) {
printf("%c", buffer2[i]); // or buufer[i] if you change to use it again
}*/
for(i=4;i<tam;i+=8) {
memcpy(v,&buffer2[i],8);
decrypt(v,k);
}
...
I don't fully understand what you are trying to accomplish, but one problem is here:
char* aux[sizeof(unsigned long)];
// ... some code ...
fread(&aux,sizeof(unsigned long),1,fp);
Understand that char* aux[sizeof(unsigned long)]; means that you are declaring a double pointer, but fread() prototype states that the destination is a single pointer:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
so what you should be doing instead is:
char aux[sizeof(unsigned long)];
// ... some code ...
fread(aux,sizeof(unsigned long),1,fp);
Don't complicate things that are not complicated!
You also do this mistake in other parts of your code, you need to re-check everything, ok? Again:
char *buffer2[28568];
fread(&buffer2,1,28568,fp);
should be:
char buffer2[28568];
fread(buffer2, 1, 28568, fp);
// or: fread(buffer2, 1, sizeof(buffer2), fp);
There are some interesting tutorials on pointers and arrays, I suggest you read some.

Resources