I want to create a simple program which would encrypt string using RSA algorithm and then decrypt it(cygwin, windows)
Here is my code
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <stdio.h>
#include <string.h>
#define KEY_LENGTH 2048
#define PUB_EXP 3
#define PRINT_KEYS
#define WRITE_TO_FILE
int main(void) {
size_t pri_len; // Length of private key
size_t pub_len; // Length of public key
char *pri_key; // Private key
char *pub_key; // Public key
char msg[KEY_LENGTH/8]; // Message to encrypt
char *encrypt = NULL; // Encrypted message
char *decrypt = NULL; // Decrypted message
char *err; // Buffer for any error messages
// Generate key pair
printf("Generating RSA (%d bits) keypair...", KEY_LENGTH);
fflush(stdout);
RSA *keypair = RSA_generate_key(KEY_LENGTH, PUB_EXP, NULL, NULL);
// To get the C-string PEM form:
BIO *pri = BIO_new(BIO_s_mem());
BIO *pub = BIO_new(BIO_s_mem());
PEM_write_bio_RSAPrivateKey(pri, keypair, NULL, NULL, 0, NULL, NULL);
PEM_write_bio_RSAPublicKey(pub, keypair);
pri_len = BIO_pending(pri);
pub_len = BIO_pending(pub);
pri_key = (char *)malloc(pri_len + 1);
pub_key = (char *)malloc(pub_len + 1);
BIO_read(pri, pri_key, pri_len);
BIO_read(pub, pub_key, pub_len);
pri_key[pri_len] = '\0';
pub_key[pub_len] = '\0';
#ifdef PRINT_KEYS
printf("\n%s\n%s\n", pri_key, pub_key);
#endif
printf("done.\n");
// Get the message to encrypt
printf("Message to encrypt: ");
fgets(msg, KEY_LENGTH-1, stdin);
msg[strlen(msg)-1] = '\0';
// Encrypt the message
encrypt = (char *)malloc(RSA_size(keypair));
int encrypt_len;
err = (char *)malloc(130);
if((encrypt_len = RSA_public_encrypt(strlen(msg)+1, (unsigned char*)msg, (unsigned char*)encrypt,
keypair, RSA_PKCS1_OAEP_PADDING)) == -1) {
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
fprintf(stderr, "Error encrypting message: %s\n", err);
return -1;
}
#ifdef WRITE_TO_FILE
// Write the encrypted message to a file
FILE *out = fopen("out.bin", "w");
fwrite(encrypt, sizeof(*encrypt), RSA_size(keypair), out);
fclose(out);
printf("Encrypted message written to file.\n");
free(encrypt);
encrypt = NULL;
// Read it back
printf("Reading back encrypted message and attempting decryption...\n");
encrypt = (char *)malloc(RSA_size(keypair));
out = fopen("out.bin", "r");
fread(encrypt, sizeof(*encrypt), RSA_size(keypair), out);
fclose(out);
#endif
// Decrypt it
decrypt = (char *)malloc(encrypt_len);
if(RSA_private_decrypt(encrypt_len, (unsigned char*)encrypt, (unsigned char*)decrypt,
keypair, RSA_PKCS1_OAEP_PADDING) == -1) {
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
fprintf(stderr, "Error decrypting message: %s\n", err);
return -1;
}
printf("Decrypted message: %s\n", decrypt);
RSA_free(keypair);
BIO_free_all(pub);
BIO_free_all(pri);
free(pri_key);
free(pub_key);
free(encrypt);
free(decrypt);
free(err);
return 0;
}
The problem I have is during compiling with command
$ gcc -I /usr/include/ -L /usr/lib/ ip.cpp -o ip.exe -lcrypto.
Here are the errors I have:
In file included from /usr/include/errno.h:9:0,
from /usr/include/openssl/err.h:140,
from ip.cpp:9:
/usr/include/sys/errno.h:14:0: warning: "errno" redefined
#define errno (*__errno())
^
In file included from /usr/lib/gcc/x86_64-w64-mingw32/4.9.2/include/stddef.h:1:0,
from /usr/include/sys/cdefs.h:45,
from /usr/include/time.h:11,
from /usr/include/openssl/asn1.h:62,
from /usr/include/openssl/rsa.h:62,
from ip.cpp:7:
/usr/x86_64-w64-mingw32/sys-root/mingw/include/stddef.h:19:0: note: this is the location of the previous definition
#define errno (*_errno())
^
In file included from /usr/include/sys/select.h:26:0,
from /usr/include/sys/types.h:85,
from /usr/include/time.h:28,
from /usr/include/openssl/asn1.h:62,
from /usr/include/openssl/rsa.h:62,
from ip.cpp:7:
/usr/include/sys/_timeval.h:40:18: error: conflicting declaration ‘typedef long int time_t’
typedef _TIME_T_ time_t;
^
In file included from /usr/x86_64-w64-mingw32/sys-root/mingw/include/stddef.h:7:0,
from /usr/lib/gcc/x86_64-w64-mingw32/4.9.2/include/stddef.h:1,
from /usr/include/sys/cdefs.h:45,
from /usr/include/time.h:11,
from /usr/include/openssl/asn1.h:62,
from /usr/include/openssl/rsa.h:62,
from ip.cpp:7:
/usr/x86_64-w64-mingw32/sys-root/mingw/include/crtdefs.h:138:20: note: previous declaration as ‘typedef __time64_t time_t’
typedef __time64_t time_t;
As you can see the first error is that errno gots defined twice. I checked and in errno.h there is this code:
#ifndef _REENT_ONLY
#define errno (*__errno())
defining _REENT_ONLY fixes this error, but then in stdio.h there is this:
#ifndef _REENT_ONLY
FILE * _EXFUN(fopen, (const char *__restrict _name, const char *__restrict _type));
so then I have fopen undefined error. Plus I don't think that defining some values without really knowing what it is for is a bad idea.
Then I tried manually commenting out the lines where data gets defined second time to just build it successfully and test the program but then I got:
/tmp/ccC3voSz.o:ip.cpp:(.rdata$.refptr._impure_ptr[.refptr._impure_ptr]+0x0): undefined reference to `_impure_ptr'
So at the end I have two problems (maybe they are even related somehow):
How to get rid of the declaration conflicts?
How to fix undefined reference to _impure_ptr
Given the following openssl example prog
#include <openssl/evp.h>
int do_crypt(FILE* in, FILE* out, int do_encrypt)
{
/* Allow enough space in output buffer for additional block */
unsigned char inbuf[1024], outbuf[1024 + EVP_MAX_BLOCK_LENGTH];
int inlen, outlen;
EVP_CIPHER_CTX* ctx;
/* Bogus key and IV: we'd normally set these from
* another source.
*/
unsigned char key[] = "0123456789abcdeF";
unsigned char iv[] = "1234567887654321";
/* Don't set key or IV right away; we want to check lengths */
ctx = EVP_CIPHER_CTX_new();
EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, NULL, NULL, do_encrypt);
OPENSSL_assert(EVP_CIPHER_CTX_key_length(ctx) == 16);
OPENSSL_assert(EVP_CIPHER_CTX_iv_length(ctx) == 16);
/* Now we can set key and IV */
EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, do_encrypt);
for (;;) {
inlen = fread(inbuf, 1, 1024, in);
if (inlen <= 0)
break;
if (!EVP_CipherUpdate(ctx, outbuf, &outlen, inbuf, inlen)) {
/* Error */
EVP_CIPHER_CTX_free(ctx);
return 0;
}
fwrite(outbuf, 1, outlen, out);
}
if (!EVP_CipherFinal_ex(ctx, outbuf, &outlen)) {
/* Error */
EVP_CIPHER_CTX_free(ctx);
return 0;
}
fwrite(outbuf, 1, outlen, out);
EVP_CIPHER_CTX_free(ctx);
return 1;
}
int main(int argc, char* argv[])
{
FILE *fpIn;
FILE *fpOut;
fpIn = fopen("text-in.txt", "rb");
fpOut = fopen("text-out.txt", "wb");
int test = do_crypt(fpIn, fpOut, 1);
fclose(fpIn);
fclose(fpOut);
return 0;
}
I would expect that
openssl aes-128-cbc -in text-in.txt -K 0123456789abcdeF -iv 1234567887654321
would create the same output. But it doesn't. The C prog can decrypt the files it encrypted. But it can't decrypt the files encrypted with openssl.
The encryption key and IV are not actually text but binary data.
When you do the encryption on the command line, the -K and -iv arguments expect their input in hex.
So the key you're passing in is actually:
\x01\x23\x45\x67\x89\xab\xcd\xef\x00\x00\x00\x00\x00\x00\x00\x00
And the IV is:
\x12\x34\x56\x78\x87\x65\x43\x21\x00\x00\x00\x00\x00\x00\x00\x00
Both have tail padding of 0's because the key that was specified was too short.
In order to match the program's output, you need to pass in the hex codes of the characters you specified. For example, 1 is 30, 2 is 31, a is 61, F is 46, and so forth:
openssl aes-128-cbc -in text-in.txt -K 30313233343536373839616263646546 -iv 31323334353637383837363534333231
I am a total beginner with the OpenSSL Library in C but was working on a code to encrypt using the libraries while taking a pass phrase as input and generating the salt,IV and key from the pass phrase. This is what I have tried till now:
int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *ciphertext)
{
char *passphrase;
printf("\nEnter a Pass Phrase:");
scanf("%s",passphrase);
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
OPENSSL_config(NULL);
EVP_CIPHER_CTX *ctx;
const EVP_CIPHER *cipher;
const EVP_MD *dgst = NULL;
unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH];
const char *salt;
int len;
int ciphertext_len;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new())) //This line causes the error
handleErrors();
cipher = EVP_get_cipherbyname("aes-256-cbc");
if(!cipher) { fprintf(stderr, "no such cipher\n"); return -1; }
dgst=EVP_get_digestbyname("md5");
if(!dgst) { fprintf(stderr, "no such digest\n"); return -1; }
if(!EVP_BytesToKey(cipher, dgst, salt, (unsigned char *) passphrase, strlen(passphrase), 1, key, iv))
{
fprintf(stderr, "EVP_BytesToKey failed\n");
return -1;
}
/* Initialise the encryption operation. IMPORTANT - ensure you use a key
* and IV size appropriate for your cipher
* In this example we are using 256 bit AES (i.e. a 256 bit key). The
* IV size for *most* modes is the same as the block size. For AES this
* is 128 bits */
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
handleErrors();
/* Provide the message to be encrypted, and obtain the encrypted output.
* EVP_EncryptUpdate can be called multiple times if necessary
*/
if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
handleErrors();
ciphertext_len = len;
/* Finalise the encryption. Further ciphertext bytes may be written at
* this stage.
*/
if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors();
ciphertext_len += len;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
EVP_cleanup();
ERR_free_strings();
return ciphertext_len;
}
I tried this out but kept getting a segmentation fault. I tried to debug and found out that the EVP_CIPHER_CTX_new() was the one cussing it. I am at my wits end right now trying to debug it and could really appreciate some help.
Thanks in advance.
This is incorrect:
char *passphrase;
printf("\nEnter a Pass Phrase:");
scanf("%s",passphrase);
char *pasphrase is just a pointer point to unknown location.
Change this to:
char passphrase[2048];
printf("\nEnter a Pass Phrase:");
scanf("%s", passphrase);
I received an RSA-2048 bit public key (256 bytes) as a file which contains just those 256 bytes. Which function in SSL enables me to load this key as an RSA structure so I can convert it to another format? This is in C code using openssl source.
I think it's the DER format, but I'm not 100% certain.
I just put this together and it seems to work correctly:
https://github.com/JonathonReinhart/rawrsa
#include <stdio.h>
#include <stdlib.h>
#include <libgen.h>
#include <openssl/bn.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
static const char* appname;
static void print_bn(const char *what, const BIGNUM *bn)
{
#ifdef DEBUG
char *str = BN_bn2hex(bn);
printf("%s (hex): %s\n", what, str);
OPENSSL_free(str);
#endif
}
static void usage(void)
{
fprintf(stderr, "Usage: %s modulus-file exponent\n", appname);
}
#define err(fmt, ...) \
fprintf(stderr, "%s: " fmt, appname, ##__VA_ARGS__)
int main(int argc, char *argv[])
{
appname = basename(argv[0]);
if (argc < 3) {
usage();
exit(1);
}
const char *modfile = argv[1];
const char *expstr = argv[2];
/* Read modulus */
FILE *mf = fopen(modfile, "rb");
if (!mf) {
err("Failed to open \"%s\": %m\n", modfile);
return 1;
}
unsigned char buf[256];
if (fread(buf, sizeof(buf), 1, mf) != 1) {
err("Failed to read %zu bytes of modulus\n", sizeof(buf));
return 1;
}
fclose(mf);
BIGNUM *mod = BN_bin2bn(buf, sizeof(buf), NULL);
if (!mod) {
err("BN_bin2bn() failed\n");
return 1;
}
print_bn("Modulus", mod);
/* Parse exponent */
BIGNUM *exp = NULL;
if (BN_dec2bn(&exp, expstr) == 0) {
err("BN_dec2bn() failed\n");
return 1;
}
print_bn("Exponent", exp);
/* Create RSA key */
RSA *rsa = RSA_new();
if (!rsa) {
err("RSA_new() failed\n");
return 1;
}
rsa->e = exp;
rsa->n = mod;
/* Write PEM-encoded RSA public key to stdout */
if (!PEM_write_RSAPublicKey(stdout, rsa)) {
err("PEM_write_RSAPublicKey() failed\n");
return 1;
}
return 0;
}
I use BN_bin2bn to create an OpenSSL bignum from raw binary data from a file. This is where we load your 256-byte modulus.
Then, I use BN_dec2bn to create a bignum from the exponent provided on the command line.
Next, I create an RSA object with RSA_new, and set the public exponent (rsa->e) and modulus (rsa->n).
Finally, I write the RSA public key to a PEM file with PEM_write_RSAPublicKey.
Example:
$ scons -Q
gcc -o main.o -c -Wall -Werror -g main.c
gcc -o rawrsa main.o -lcrypto
$ ./rawrsa key.bin 65537
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEA9cFHSTQ6h1Ls/vx7B+V/84XVlLxUU1dU1mEr9ROAqWrZtfasvx2E
21lbva+AdJ/B4u6fGVhCEMgekXsRB65CqZfwL3DFL6tqam6GvrOyvZgAlQKrA54w
DaKMT8Kfg2I2K9W/HCkCOHczhuHhjFmeiV9BuQgpmcPcNz6UXBwU05d3g6oM/X4m
lEhEsaH4bqo1qsMX6jp6WnsR13GEfsYoYVmHgEbnKJyGpsoRVW6HQXLHvef9XLEJ
v9n7nLdHToya75svxJ3v9JugD3n6PiC48085/FWb9980o4hmG9iW5rehm4Dlui8c
TDnHkQSrvi9WLlZ+S8hdtwDRN/pVVTjgPAIDAQAB
-----END RSA PUBLIC KEY-----
I am trying to read a file(.txt) in this case and encrypting/decrypting it with AES256CBC using EVP api of openssl.(read(plain.txt)->create(encrypt.txt)->create(decrypt.txt))
# include <stdio.h>
# include <stdlib.h>
# include <openssl/evp.h>
# include <openssl/aes.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <unistd.h>
# include <string.h>
# include <assert.h>
# include <error.h>
# include "debug.h"
# define SIZE 32
char buf[SIZE];
int aes_init(unsigned char* pwd, unsigned int pwd_len, unsigned char * salt, EVP_CIPHER_CTX *e_ctx, EVP_CIPHER_CTX *d_ctx)
{
int i, rounds =5; /* rounds */
unsigned char key[32], iv[32];
i = EVP_BytesToKey(EVP_aes_256_cbc(),EVP_sha1(),salt,pwd,pwd_len,rounds,key,iv);
if(i != 32)
{
printf("\n Error,Incorrect key size generated:%d:\n",i);
return -1;
}
EVP_CIPHER_CTX_init(e_ctx);
EVP_EncryptInit_ex(e_ctx, EVP_aes_256_cbc(), NULL, key, iv);
EVP_CIPHER_CTX_init(d_ctx);
EVP_DecryptInit_ex(d_ctx, EVP_aes_256_cbc(), NULL, key, iv);
return 0;
}
unsigned char* aes_encrypt(EVP_CIPHER_CTX *e,unsigned char * plain_text, unsigned int * len ) /* this function encryptes the file:fd is passed as parameter */
{
int ci_len = (*len) + AES_BLOCK_SIZE;
int flen =0;
unsigned char * cipher_text = malloc(ci_len);
EVP_EncryptInit_ex(e, NULL, NULL, NULL, NULL); /* allows reusing of e for multiple cipher cycles */
EVP_EncryptUpdate(e, cipher_text, &ci_len, plain_text, *len); /* Update cipher text */
EVP_EncryptFinal_ex(e, cipher_text+ci_len, &flen); /* updates the remaining bytes */
*len = ci_len + flen;
return cipher_text;
}
unsigned char* aes_decrypt(EVP_CIPHER_CTX *e, unsigned char * c_text, unsigned int * len)
{
int pi_len = (*len);
int flen = 0;
unsigned char * plain_text = malloc(pi_len);
EVP_DecryptInit_ex(e, NULL, NULL, NULL, NULL);
EVP_DecryptUpdate(e, plain_text, &pi_len, c_text, *len);
EVP_DecryptFinal_ex(e, plain_text+pi_len, &flen);
(*len) = pi_len + flen;
return plain_text;
}
int main(int argc,char **argv)
{
if(argc != 2)
{
perror("\n Error:\nCorrect Usage: Enter Password to be used");
exit(-1);
}
EVP_CIPHER_CTX en,de; /* The EVP structure which keeps track of all crypt operations see evp.h for details */
int in, out, fd, dec,i =0; /* fd for input and output files and random dev*/
unsigned int pwd_len = strlen((const char *)argv[1]); /* Length of the pwd supplied by the user */
unsigned char *pwd =(unsigned char*) argv[1]; /* Pointer to the pwd supplied by the user */
unsigned int rd= 0;
unsigned char salt[8];
unsigned char * encry = NULL, *decry = NULL;
i =0;
if((in = open("plain.txt",O_RDONLY)) == -1) /* Opening a plain text file for encryption */
{
perror("\n Error,Opening file for reading::");
exit(-1);
}
if((fd = open("/dev/random", O_RDONLY)) == -1)
{
perror("\n Error,Opening /dev/random::");
exit(-1);
}
else
{
if(read(fd,salt,8) == -1)
{
perror("\n Error,reading from /dev/random::");
exit(-1);
}
}
if(aes_init(pwd,pwd_len,(unsigned char*) salt,&en,&de)) /* Generating Key and IV and initializing the EVP struct */
{
perror("\n Error, Cant initialize key and IV:");
return -1;
}
if((out = open("encrypt.txt",O_RDWR|O_CREAT,0400 | 0200)) == -1)
{
dbug_p("ENC%d",out);
perror("\n Error,Opening the file to be written::");
exit(-1);
}
rd =0;
while((rd = read(in,buf,SIZE)) >0)
{
dbug_p("\nREAD::%s::%d*\n",buf,rd);
encry = aes_encrypt(&en,(unsigned char*) buf, &rd);
if((write(out,encry,rd)) != rd)
{
perror("\n Error,Required encrypted bytes not written::");
exit(-1);
}
free(encry);
}
rd =0;
if((dec = open("dec22.txt",O_RDWR|O_CREAT,0400 | 0200)) == -1)
{
dbug_p("dec%d",dec);
perror("\n Error,Opening the decrypting o/p file::");
exit(-1);
}
if((lseek(out,0,SEEK_SET)) != 0) perror("\n Error:setting lseek::");
for(i=0;i<SIZE;i++) buf[i] =0;
while((rd = read(out,dbuf,SIZE)) >0)
{
decry = aes_decrypt(&de,(unsigned char*) dbuf, &rd);
if((write(dec,decry,rd)) != rd)
{
perror("\n Error,Required decrypted bytes not written::");
exit(-1);
}
free(decry);
}
close(in);
close(fd);
EVP_CIPHER_CTX_cleanup(&en);
EVP_CIPHER_CTX_cleanup(&de);
return 0;
}
My problem was that my when i decrypt an encrypted file i get a file which is not properly decrypted (e.g. correct stringgarbagecorrect stringgarbage ...)
abhi#ubuntu:~/mpro/EFF$ cat plain.txt
Today is tuesday
tomorrow is wednesday
then thursday and friday and saturday
finally sunday
Decrypted file
cat dec22.txt
Today is tuesdayw)Q������O-%�A�8���R��.�O���and saturday
finally sunday
What can be the reason for this. Is it reading something else also or i am making any foolish error somewhere.
EDIT: If I just encrypt an array (tried with 36char long) it correctly encrypted and decrypted without printing any garbage.
I guess i am missing(not handling) some *nix file structure details ..??
Or is there any better way to do this encryption on a file.?
Many thanks
I think your analysis is wrong. This loop is problematic:
while((rd = read(in,buf,SIZE)) >0)
{
dbug_p("\nREAD::%s::\n",buf);
encry = aes_encrypt(&en,(unsigned char*) buf, &rd);
dbug_p("\n EN::%s::\n",encry);
decry = aes_decrypt(&de,(unsigned char*) encry,&rd);
dbug_p("\n DE::%s::\n",decry);
free(encry);
free(decry);
}
Firstly because you print using %s which expects a zero terminator. However, the encrypted/decrypted data is not zero terminated. Instead, you should print rd characters using a loop like for (i = 0; i < rd; i++) printf("%02x "); - this is why your analysis of the problem is likely flawed.
Secondly, I assume that in your real problem, you are reading SIZE bytes at a time and sending them to aes_decrypt() separately. This will fail because EVP_DecryptFinal_ex() is getting called too early (before all the encrypted blocks were read). You have two options. Either you send the read bytes through EVP_DecryptUpdate() in each loop iteration, and call EVP_DecryptFinal() after completing the loop (and init accordingly before the loop), or you read the whole file into a buffer first, and then send it through aes_decrypt() in one go.
Or in other words, you need to send the whole data block resulting from aes_encrypt() later to aes_decrypt(). You cannot send them in different chunks, unless you split the functions up and use the EVP "update" functions on the separate chunks.
while((rd = read(in,buf,SIZE)) >0)
{
dbug_p("\nREAD::%s::%d*\n",buf,rd);
encry = aes_encrypt(&en,(unsigned char*) buf, &rd);
and,
unsigned char* aes_encrypt(EVP_CIPHER_CTX *e,unsigned char * plain_text, unsigned int * len ) /* this function encryptes the file:fd is passed as parameter */
{
int ci_len = (*len) + AES_BLOCK_SIZE;
int flen =0;
unsigned char * cipher_text = malloc(ci_len);
EVP_EncryptInit_ex(e, NULL, NULL, NULL, NULL); /* allows reusing of e for multiple cipher cycles */
EVP_EncryptUpdate(e, cipher_text, &ci_len, plain_text, *len); /* Update cipher text */
EVP_EncryptFinal_ex(e, cipher_text+ci_len, &flen); /* updates the remaining bytes */
You are calling EVP_EncryptFinal_ex multiple times. It is supposed to be called only once at the end.
Same is true for how you are doing decryption.
Here is a simple example from the man page on how to do encrypt.
Have a similar function for decryption and it should work.
int do_crypt(char *outfile)
{
unsigned char outbuf[1024];
int outlen, tmplen;
/* Bogus key and IV: we'd normally set these from
* another source.
*/
unsigned char key[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
unsigned char iv[] = {1,2,3,4,5,6,7,8};
char intext[] = "Some Crypto Text";
EVP_CIPHER_CTX ctx;
FILE *out;
EVP_CIPHER_CTX_init(&ctx);
EVP_EncryptInit_ex(&ctx, EVP_bf_cbc(), NULL, key, iv);
if(!EVP_EncryptUpdate(&ctx, outbuf, &outlen, intext, strlen(intext)))
{
/* Error */
return 0;
}
/* Buffer passed to EVP_EncryptFinal() must be after data just
* encrypted to avoid overwriting it.
*/
if(!EVP_EncryptFinal_ex(&ctx, outbuf + outlen, &tmplen))
{
/* Error */
return 0;
}
outlen += tmplen;
EVP_CIPHER_CTX_cleanup(&ctx);
/* Need binary mode for fopen because encrypted data is
* binary data. Also cannot use strlen() on it because
* it wont be null terminated and may contain embedded
* nulls.
*/
out = fopen(outfile, "wb");
fwrite(outbuf, 1, outlen, out);
fclose(out);
return 1;
}
the following example is reading a file as your case. See how Update (called multiple times) and Final (once at the end) routines are used.
int do_crypt(FILE *in, FILE *out, int do_encrypt)
{
/* Allow enough space in output buffer for additional block */
inbuf[1024], outbuf[1024 + EVP_MAX_BLOCK_LENGTH];
int inlen, outlen;
/* Bogus key and IV: we'd normally set these from
* another source.
*/
unsigned char key[] = "0123456789";
unsigned char iv[] = "12345678";
/* Don't set key or IV because we will modify the parameters */
EVP_CIPHER_CTX_init(&ctx);
EVP_CipherInit_ex(&ctx, EVP_rc2(), NULL, NULL, NULL, do_encrypt);
EVP_CIPHER_CTX_set_key_length(&ctx, 10);
/* We finished modifying parameters so now we can set key and IV */
EVP_CipherInit_ex(&ctx, NULL, NULL, key, iv, do_encrypt);
for(;;)
{
inlen = fread(inbuf, 1, 1024, in);
if(inlen <= 0) break;
if(!EVP_CipherUpdate(&ctx, outbuf, &outlen, inbuf, inlen))
{
/* Error */
EVP_CIPHER_CTX_cleanup(&ctx);
return 0;
}
fwrite(outbuf, 1, outlen, out);
}
if(!EVP_CipherFinal_ex(&ctx, outbuf, &outlen))
{
/* Error */
EVP_CIPHER_CTX_cleanup(&ctx);
return 0;
}
fwrite(outbuf, 1, outlen, out);
EVP_CIPHER_CTX_cleanup(&ctx);
return 1;
}