I wrote this code to encrypt and decrypt the contents of folder, both function works well when encrypting normal files but when im changing the folder to system folder, program crashes and when i check the latest file before crashing, im not able to open some of them (File is Open in Another Program), in some of them i just can't make changes.
i'm handling all errors i think, but it still keep crashing when it reachs to opened file by another program, how to solve this problem to ignore these types of files and keep continue instead of crashing?
and the structure is not important to post i think.
char ListFiles(const wchar_t* folder, CIPHER* conf)
{
wchar_t wildcard[MAX_PATH + 1];
swprintf(wildcard, sizeof(wildcard) / sizeof(*wildcard), L"%s\\*", folder);
WIN32_FIND_DATAW fd;
HANDLE handle = FindFirstFileW(wildcard, &fd);
if (handle == INVALID_HANDLE_VALUE) return 1;
do
{
if (wcscmp(fd.cFileName, L".") == 0 || wcscmp(fd.cFileName, L"..") == 0)
continue;
wchar_t path[MAX_PATH + 1];
swprintf(path, sizeof(path) / sizeof(*path), L"%s\\%s", folder, fd.cFileName);
if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && !(fd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM))
ListFiles(path, &conf);
if (fd.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE && !(fd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM))
{
wprintf(L"%s\n", path);
FILE* f_dec;
FILE* f_input = _wfopen(path, L"rb");
FILE* f_enc = _wfopen(wcscat(path, L".encrypted"), L"wb");
if (!f_input || !f_enc) {
fprintf(stderr, "fopen error: %s\n", strerror(errno));
continue;
}
conf->encrypt = 1; // encryption
if (AES_L(conf, f_input, f_enc) != 0)
continue;
f_enc = _wfopen(path, L"rb");
f_dec = _wfopen(wcscat(path, L".decrypted"), L"wb");
if (!f_dec || !f_enc) {
fprintf(stderr, "ERROR: fopen error: %s\n", strerror(errno));
continue;
}
conf->encrypt = 0; // decryption
if (AES_L(conf, f_enc, f_dec) != 0)
continue;
puts("\n\n");
}
} while (FindNextFileW(handle, &fd));
FindClose(handle);
return 0;
}
char AES_L(CIPHER* params, FILE* ifp, FILE* ofp)
{
unsigned int inlen, outlen;
unsigned char* inbuf = (unsigned char*)malloc(params->bufsize);
unsigned char* outbuf = (unsigned char*)malloc(params->bufsize + EVP_MAX_BLOCK_LENGTH);
if (inbuf == NULL || outbuf == NULL)
{
printf("memory cannot be allocated\n");
cleanup(ifp, ofp, inbuf, outbuf);
return 1;
}
EVP_CIPHER_CTX* ctx;
ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL) {
fprintf(stderr, "ERROR: EVP_CIPHER_CTX_new failed. OpenSSL error: %s\n",
ERR_error_string(ERR_get_error(), NULL));
cleanup(ifp, ofp, inbuf, outbuf);
return 1;
}
if (!EVP_CipherInit_ex(ctx, params->cipher_type, NULL, params->key, params->iv, params->encrypt)) {
fprintf(stderr, "ERROR: EVP_CipherInit_ex failed. OpenSSL error: %s\n",
ERR_error_string(ERR_get_error(), NULL));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf);
return 1;
}
while (1) {
// Read in data in blocks until EOF. Update the ciphering with each read.
inlen = fread(inbuf, sizeof(*inbuf), params->bufsize, ifp);
if (ferror(ifp)) {
fprintf(stderr, "ERROR: fread error: %s\n", strerror(errno));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf, errno);
return 1;
}
if (!EVP_CipherUpdate(ctx, outbuf, &outlen, inbuf, inlen)) {
fprintf(stderr, "ERROR: EVP_CipherUpdate failed. OpenSSL error: %s\n",
ERR_error_string(ERR_get_error(), NULL));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf);
return 1;
}
fwrite(outbuf, sizeof(*outbuf), outlen, ofp);
if (ferror(ofp)) {
fprintf(stderr, "ERROR: fwrite error: %s\n", strerror(errno));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf, errno);
return 1;
}
if (inlen < params->bufsize) /* Reached End of file */
break;
}
/* Now cipher the final block and write it out to file */
if (!EVP_CipherFinal_ex(ctx, outbuf, &outlen)) {
fprintf(stderr, "ERROR: EVP_CipherFinal_ex failed. OpenSSL error: %s\n",
ERR_error_string(ERR_get_error(), NULL));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf);
return 1;
}
fwrite(outbuf, sizeof(*outbuf), outlen, ofp);
if (ferror(ofp)) {
fprintf(stderr, "ERROR: fwrite error: %s\n", strerror(errno));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf);
return 1;
}
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf);
return 0;
}
update:
void cleanup(FILE* ifp, FILE* ofp, unsigned char* inputBuf, unsigned char* outputBuf)
{
free(inputBuf);
free(outputBuf);
fclose(ifp);
fclose(ofp);
}
typedef struct {
unsigned int key_size;
unsigned int block_size;
unsigned int bufsize;
unsigned char* key;
unsigned char* iv;
unsigned int encrypt;
const EVP_CIPHER* cipher_type;
} CIPHER;
I see some problems with your code, although it's hard to know if they can lead to a crash without the rest of the code (for instance, we can't see the cleanup method), or how you create and initialize params.
The first problem is that you may be leaking file handles. When you open the files in ListFiles you open them in pairs, then check if any of them is NULL and if one is, you go on with the loop.
FILE* f_input = _wfopen(path, L"rb");
FILE* f_enc = _wfopen(wcscat(path, L".encrypted"), L"wb");
if (!f_input || !f_enc) {
fprintf(stderr, "fopen error: %s\n", strerror(errno));
continue;
}
What if f_input is opened correctly but f_enc fails? The source file would remain open until the program ends. You should check each of them separately.
A similar problem arises when you allocate memory in AES_L:
unsigned char* inbuf = (unsigned char*)malloc(params->bufsize);
unsigned char* outbuf = (unsigned char*)malloc(params->bufsize + EVP_MAX_BLOCK_LENGTH);
if (inbuf == NULL || outbuf == NULL)
{
printf("memory cannot be allocated\n");
return 1;
}
If one of the buffers (probably inbuf) is allocated correctly but outbuf fails, you would be leaking memory because you don't free the buffer that was allocated correctly (although, to be honest, I don't think this is directly the problem with the crash because this would happen in situations when you are already very low on memory).
Another problem may appear when you create the path for the encrypted and decrypted files. The path buffer is of size MAX_PATH+1, which is enough for the original file name, but then you perform a couple of wcscat operations that lead additional data to be added to the path. What if the original file name was already almost in the MAX_PATH limit? When you performed the wcscat you would be overflowing a buffer in the stack, which may also lead to a crash.
And finally, ListFiles is recursive, so if there are many nested calls you may be running out of stack, which would also lead to a crash (in fact, from the problems I mention I think it's the main suspect). I would make it iterative.
Anyway, it's very difficult to know if the crash is due to these problems, and your best option is running it in the debugger. The error message from the crash will tell you a lot of information to identify the reason.
Related
I got this below function file_encrypt_decrypt for encryption and decryption of a file using AES256 CBC from here.
If I'm doing encryption and decryption both from same program, (main function given at the end) encryption and decryption is working properly. Though both the time same function is called and ctx is initiated again.
If I'm commenting the encryption part, passing the above created encrypted_file, decryption is failing with error:
ERROR: EVP_CipherFinal_ex failed. OpenSSL error: error:06065064:lib(6):func(101):reason(100)
[[meaningful]] OpenSSL error: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
Somewhere people are talking about some padding length issue. But I can't figure it out properly.
Also how the same function is working properly if encryption is done at the same program but separately, it is failing?
Some guidance will be appreciated.
PS: Instead of a common function, I've tried separate functions for encryption and decryption with EVP_DecryptInit_ex(), EVP_DecryptUpdate(), EVP_DecryptFinal_ex() and similar for encryption but of no effect.
Full Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/aes.h>
#include <openssl/rand.h>
#define ERR_EVP_CIPHER_INIT -1
#define ERR_EVP_CIPHER_UPDATE -2
#define ERR_EVP_CIPHER_FINAL -3
#define ERR_EVP_CTX_NEW -4
#define AES_256_KEY_SIZE 32
#define AES_BLOCK_SIZE 16
#define BUFSIZE 1024
typedef struct _cipher_params_t{
unsigned char *key;
unsigned char *iv;
unsigned int encrypt;
const EVP_CIPHER *cipher_type;
}cipher_params_t;
void cleanup(cipher_params_t *params, FILE *ifp, FILE *ofp, int rc){
free(params);
fclose(ifp);
fclose(ofp);
exit(rc);
}
void file_encrypt_decrypt(cipher_params_t *params, FILE *ifp, FILE *ofp){
// Allow enough space in output buffer for additional block
int cipher_block_size = EVP_CIPHER_block_size(params->cipher_type);
unsigned char in_buf[BUFSIZE], out_buf[BUFSIZE + cipher_block_size];
int num_bytes_read, out_len;
EVP_CIPHER_CTX *ctx;
ctx = EVP_CIPHER_CTX_new();
if(ctx == NULL){
fprintf(stderr, "ERROR: EVP_CIPHER_CTX_new failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL));
cleanup(params, ifp, ofp, ERR_EVP_CTX_NEW);
}
// Don't set key or IV right away; we want to check lengths
if(!EVP_CipherInit_ex(ctx, params->cipher_type, NULL, NULL, NULL, params->encrypt)){
fprintf(stderr, "ERROR: EVP_CipherInit_ex failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL));
cleanup(params, ifp, ofp, ERR_EVP_CIPHER_INIT);
}
OPENSSL_assert(EVP_CIPHER_CTX_key_length(ctx) == AES_256_KEY_SIZE);
OPENSSL_assert(EVP_CIPHER_CTX_iv_length(ctx) == AES_BLOCK_SIZE);
// Now we can set key and IV
if(!EVP_CipherInit_ex(ctx, NULL, NULL, params->key, params->iv, params->encrypt)){
fprintf(stderr, "ERROR: EVP_CipherInit_ex failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(params, ifp, ofp, ERR_EVP_CIPHER_INIT);
}
while(1){
// Read in data in blocks until EOF. Update the ciphering with each read.
num_bytes_read = fread(in_buf, sizeof(unsigned char), BUFSIZE, ifp);
if (ferror(ifp)){
fprintf(stderr, "ERROR: fread error: %s\n", strerror(errno));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(params, ifp, ofp, errno);
}
if(!EVP_CipherUpdate(ctx, out_buf, &out_len, in_buf, num_bytes_read)){
fprintf(stderr, "ERROR: EVP_CipherUpdate failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(params, ifp, ofp, ERR_EVP_CIPHER_UPDATE);
}
fwrite(out_buf, sizeof(unsigned char), out_len, ofp);
if (ferror(ofp)) {
fprintf(stderr, "ERROR: fwrite error: %s\n", strerror(errno));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(params, ifp, ofp, errno);
}
if (num_bytes_read < BUFSIZE) {
// Reached End of file
break;
}
}
// Now cipher the final block and write it out to file
if(!EVP_CipherFinal_ex(ctx, out_buf, &out_len)){
fprintf(stderr, "ERROR: EVP_CipherFinal_ex failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(params, ifp, ofp, ERR_EVP_CIPHER_FINAL);
}
fwrite(out_buf, sizeof(unsigned char), out_len, ofp);
if (ferror(ofp)) {
fprintf(stderr, "ERROR: fwrite error: %s\n", strerror(errno));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(params, ifp, ofp, errno);
}
EVP_CIPHER_CTX_cleanup(ctx);
}
int main(int argc, char *argv[]) {
FILE *f_input, *f_enc, *f_dec;
// Make sure user provides the input file
if (argc != 2) {
printf("Usage: %s /path/to/file\n", argv[0]);
return -1;
}
cipher_params_t *params = (cipher_params_t *)malloc(sizeof(cipher_params_t));
if (!params) {
// Unable to allocate memory on heap
fprintf(stderr, "ERROR: malloc error: %s\n", strerror(errno));
return errno;
}
// Key to use for encrpytion and decryption
unsigned char key[AES_256_KEY_SIZE];
// Initialization Vector
unsigned char iv[AES_BLOCK_SIZE];
// Generate cryptographically strong pseudo-random bytes for key and IV
if (!RAND_bytes(key, sizeof(key)) || !RAND_bytes(iv, sizeof(iv))) {
// OpenSSL reports a failure, act accordingly
fprintf(stderr, "ERROR: RAND_bytes error: %s\n", strerror(errno));
return errno;
}
params->key = key;
params->iv = iv;
// Indicate that we want to encrypt
params->encrypt = 1;
// Set the cipher type you want for encryption-decryption
params->cipher_type = EVP_aes_256_cbc();
// Open the input file for reading in binary ("rb" mode)
f_input = fopen(argv[1], "rb");
if (!f_input) {
// Unable to open file for reading
fprintf(stderr, "ERROR: fopen error: %s\n", strerror(errno));
return errno;
}
// Open and truncate file to zero length or create ciphertext file for writing
f_enc = fopen("encrypted_file", "wb");
if (!f_enc) {
// Unable to open file for writing
fprintf(stderr, "ERROR: fopen error: %s\n", strerror(errno));
return errno;
}
// Encrypt the given file
file_encrypt_decrypt(params, f_input, f_enc);
// Encryption done, close the file descriptors
fclose(f_input);
fclose(f_enc);
// Decrypt the file
// Indicate that we want to decrypt
params->encrypt = 0;
// Open the encrypted file for reading in binary ("rb" mode)
f_input = fopen("encrypted_file", "rb");
if (!f_input) {
// Unable to open file for reading
fprintf(stderr, "ERROR: fopen error: %s\n", strerror(errno));
return errno;
}
// Open and truncate file to zero length or create decrypted file for writing
f_dec = fopen("decrypted_file", "wb");
if (!f_dec) {
// Unable to open file for writing
fprintf(stderr, "ERROR: fopen error: %s\n", strerror(errno));
return errno;
}
// Decrypt the given file
file_encrypt_decrypt(params, f_input, f_dec);
// Close the open file descriptors
fclose(f_input);
fclose(f_dec);
// Free the memory allocated to our structure
free(params);
return 0;
}
The code generates a new key and a new IV with each run. So if only the encryption part is commented out, then two different key / IV pairs are generated and used for encryption and decryption, which leads to the observed error message. If for testing purposes a fixed key / IV pair is used instead of the each time freshly generated pair, the code works as expected.
In general, the key / IV pair used for encryption must also be used for decryption. Regarding the IV, in practice a random IV is usually generated during encryption. After its use, it's simply added in front of the ciphertext (since the IV isn't secret), so that it can be reconstructed and used during decryption.
In the following code, I need a unique filename, do some stuff with it, and let it be. It is about converting a .class file to binary, let us call it compilation.
It works perfectly when run in isolation or done 3 times at a time; however, I run into issues when I start up many multiple processes (e.g., 7) where one or more of my compilations fail.
This is the code:
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
static unsigned int numFiles = 0;
static unsigned long numBytes = 0;
FILE* rawf;
char* raw_file_name_end = ".raw_ujc";
char * rawfilename;
static void byte(unsigned char v){
if(numBytes) printf(", ");
printf((numBytes & 0x0F) ? "0x%02X" : "\n\t0x%02X", v);
fwrite(&v,sizeof(v),1,rawf);
numBytes++;
}
int main(int argc, char** argv){
const char* self = argv[0];
int c;
const char* classCvt = 0;
long len;
if(argc == 1){
fprintf(stderr, "USAGE: %s [-c <path_to_classCvt>] <file 1> [<file 2> [ <file 3> [...]]] > result.c\n", self);
return -1;
}
argv++;
argc--;
if(argv[0][0] == '-' && argv[0][1] == 'c' && !argv[0][2]){
classCvt = argv[1];
argv += 2;
argc -= 2;
}
printf("\nService optimized bytecode = {\n\t");
while(argc--){
char* filename = *argv;
rawfilename = malloc(sizeof(char) * (strlen(filename)-strlen(".class")) + sizeof(char) * strlen(raw_file_name_end)+1);
strncpy(rawfilename,filename,(strlen(filename)-strlen(".class")));
strcat(rawfilename,raw_file_name_end);
fprintf(stderr, "rawfilename after alloc: %s \n", rawfilename);
if(classCvt){
char* t;
filename = tempnam(NULL, NULL);
if(!filename){
fprintf(stderr, "%s: failed to create a tempfile: %d\n", self, errno);
return -10;
}
t = malloc(strlen(filename) + strlen(classCvt) + strlen(*argv) + 32);
if(!t){
fprintf(stderr, "%s: failed to alloc a small string. This is unlikely\n", self);
free(t);
return -11;
}
sprintf(t, "%s < %s > %s", classCvt, *argv, filename);
if(system(t)){
fprintf(stderr, "%s: system() fail: %d\n", self, errno);
free(t);
return -12;
}
free(t);
}
printf("filename is %s\n",filename);
FILE* f = fopen(filename, "r");
rawf = fopen(rawfilename, "wb");
if(filename != *argv){
unlink(filename);
free(filename);
}
if(!f){
fprintf(stderr, "%s: failed to open '%s': %d\n", self, *argv, errno);
fclose(f);
return -2;
}
if(!f){
fprintf(stderr, "%s: failed to open '%s': %d\n", self, *argv, errno);
fclose(f);
return -2;
}
if(fseek(f, 0, SEEK_END)){
fprintf(stderr, "%s: failed to seek(1) in '%s': %d\n", self, *argv, errno);
fclose(f);
return -3;
}
len = ftell(f);
if(len < 0){
fprintf(stderr, "%s: failed to tell in '%s': %d\n", self, *argv, errno);
fclose(f);
return -4;
}
if(fseek(f, 0, SEEK_SET)){
fprintf(stderr, "%s: failed to seek(2) in '%s': %d\n", self, *argv, errno);
fclose(f);
return -5;
}
if(len > 0x00FFFFFFUL){
fprintf(stderr, "%s: file '%s' is %lu bytes, while maximum allowable size is %lu.\n", self, *argv, len, 0x00FFFFFFUL);
fclose(f);
return -6;
}
byte(len >> 16);
byte(len >> 8);
byte(len);
while((c = fgetc(f)) != EOF){
byte(c);
}
numFiles++;
fclose(f);
fclose(rawf);
argv++;
}
byte(0);
byte(0);
byte(0);
printf("\n};\n");
fprintf(stderr, "%s: processed %u files, producing %lu (0x%lX) bytes of output\n", self, numFiles, numBytes, numBytes);
fprintf(stderr, "rawfilename at end: %s \n", rawfilename);
free(rawfilename);
return 0;
}
After looking around, people recommend using mkstemp(); however, as you can see, I actually do need the filename in several places.
I tried adjusting this but keep running into errors. How can I safely adjust this work method?
From the manpage for mkstemp
int mkstemp(char *template);
The mkstemp() function generates a unique temporary filename from template, creates and opens the file, and returns an open file descriptor for the file.
The last six characters of template must be "XXXXXX" and these are
replaced with a string that makes the filename unique. Since it will
be modified, template must not be a string constant, but should be
declared as a character array.
The file is created with permissions 0600, that is, read plus write
for owner only. The returned file descriptor provides both read and
write access to the file. The file is opened with the open(2) O_EXCL
flag, guaranteeing that the caller is the process that creates the
file.
so if you need the filename, you can find it in the template argument passed to mkstemp.
I'm writing code that's supposed to verify that a .txt file is a certain format.
I wrote my code as I saw in a tutorial and in the website
and for some reason my program doesn't even print my file.
Can you tell me what I'm doing wrong?
The code will do something far more complex, but I'm still trying to work on my basics.
Here's my code so far:
int main(int argc, char *argv[]) {
/* argv[0] = name of my running file
* argv[1] = the first file that i receive
*/
define MAXBUFLEN 4096
char source[MAXBUFLEN + 1];
int badReturnValue = 1;
char *error = "Error! trying to open the file ";
if (argc != 2) {
printf("please supply a file \n");
return badReturnValue;
}
char *fileName = argv[1];
FILE *fp = fopen(argv[1], "r"); /* "r" = open for reading */
if (fp != NULL) {
size_t newLen = fread(&source, sizeof(char), MAXBUFLEN, fp);
if (ferror(fp) != 0) {
printf("%s %s", error, fileName);
return badReturnValue;
}
int symbol;
while ((symbol = getc(fp)) != EOF) {
putchar(symbol);
}
printf("finish");
fclose(fp);
}
else {
printf("%s %s", error, fileName);
return badReturnValue;
}
}
I think you need a bit more explanations:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
// there might be a macro BUFLEN defined in stdio
// which size is optimized for reading in chunks.
// Test if avaiable otherwise define it
#ifndef BUFLEN
# define BUFLEN 4096
#endif
int main(int argc, char *argv[])
{
char source[BUFLEN];
char *filename;
FILE *fp;
size_t fpread, written;
char c;
int ret_fclose;
if (argc != 2) {
fprintf(stderr, "Usage: %s filename\n", argv[0]);
exit(EXIT_FAILURE);
}
// reset errno, just in case
errno = 0;
// work on copy
filename = malloc(strlen(argv[1]) + 1);
if (filename == NULL) {
fprintf(stderr, "Allocating %zu bytes failed\n", strlen(argv[1]) + 1);
exit(EXIT_FAILURE);
}
filename = strcpy(filename, argv[1]);
// try to open the file at 'filename'
fp = fopen(filename, "r");
if (fp == NULL) {
fprintf(stderr, "Opening file \"%s\" filename failed\n", filename);
// errno might got set to something usable, check and print
if (errno != 0) {
fprintf(stderr, "Error: %s\n", strerror(errno));
}
exit(EXIT_FAILURE);
}
// You have two options here. One is to read in chunks of MAXBUFLEN
while ((fpread = fread(&source, 1, BUFLEN, fp)) > 0) {
// Do something with the stuff we read into "source"
// we do nothing with it here, we just write to stdout
written = fwrite(&source, 1, fpread, stdout);
// you can use 'written' for error check when writing to an actual file
// but it is unlikely (but not impossible!) with stdout
// test if we wrote what we read
if ((fpread - written) != 0) {
fprintf(stderr, "We did not write what we read. Diff: %d\n",
(int) (fpread - written));
}
}
// fread() does not distinguish between EOF and error, we have to check by hand
if (feof(fp)) {
// we have read all, exit
puts("\n\n\tfinish\n");
// No, wait, we want to do it again in a different way, so: no exit
// exit(EXIT_SUCCESS);
} else {
// some error may have occured, check
if (ferror(fp)) {
fprintf(stderr, "Something bad happend while reading \"%s\"\n", filename);
if (errno != 0) {
fprintf(stderr, "Error: %s\n", strerror(errno));
}
exit(EXIT_FAILURE);
}
}
// the other way is to read it byte by byte
// reset the filepointers/errors et al.
rewind(fp);
// rewind() should have reseted errno, but better be safe than sorry
errno = 0;
printf("\n\n\tread and print \"%s\" again\n\n\n\n", filename);
// read one byte and print it until end of file
while ((c = fgetc(fp)) != EOF) {
// just print. Gathering them into "source" is left as an exercise
fputc(c, stdout);
}
// clean up
errno = 0;
ret_fclose = fclose(fp);
// even fclose() might fail
if (ret_fclose == EOF) {
fprintf(stderr, "Something bad happend while closing \"%s\"\n", filename);
if (errno != 0) {
fprintf(stderr, "Error: %s\n", strerror(errno));
}
exit(EXIT_FAILURE);
}
// The macros EXIT_FAILURE and EXIT_SUCCESS are set to the correct values for
// the OS to tell it if we had an eror or not.
// Using exit() is noot necessary here but there exits teh function atexit()
// that runs a given function (e.g: clean up, safe content etc.) when called
exit(EXIT_SUCCESS);
}
You read from the file twice but only print once.
If the file is to small the first reading will read all of the contents, and the second reading will not produce anything so you don't print anything.
I believe you have to reset the pointer after using fread.
Try fseek(fp, SEEK_SET, 0) to reset the pointer to the beginning of the file. Then print the file.
I'm new with cryptography, so I decided to create simple program that would open a file encrypt data, put it in etest.txt, then open this file decrypt it and put it indetest.txt.I know it sounds really weired but its for educational purposes. so here is my code. I've read many topics about this problem but none of them worked for me.
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <stdio.h>
#include <string.h>
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 = malloc(256); // Message to encrypt
char *encrypt = NULL; // Encrypted message
char *decrypt = NULL; // Decrypted message
char *err; // Buffer for any error messages
size_t red;
RSA *keypair = RSA_generate_key(2048, 3, NULL, NULL);
FILE *in = fopen("test.txt", "r");
FILE *out = fopen("etest.txt", "w");
if(in == NULL)
{
printf("in Error is %d (%s).\n", errno, strerror(errno));
}
if(out == NULL)
{
printf("out Error is %d (%s).\n", errno, strerror(errno));
}
encrypt = malloc(RSA_size(keypair));
for(;;)
{
red = fread(msg, 1, RSA_size(keypair)-42, in);
if((RSA_public_encrypt(RSA_size(keypair)-42, (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);
}
if(fwrite(encrypt, 1, strlen(encrypt), out) == 1)
{
printf("fwrite Error is %d (%s).\n", errno, strerror(errno));
}
if(feof(in))
{
break;
}
}
fclose(in);
fclose(out);
in = fopen("etest.txt", "r");
out = fopen("dtest.txt", "w");
if(in == NULL)
{
printf("in Error is %d (%s).\n", errno, strerror(errno));
}
if(out == NULL)
{
printf("out Error is %d (%s).\n", errno, strerror(errno));
}
decrypt = malloc(RSA_size(keypair));
for(;;)
{
red = fread(msg, 1, 256, in);
if(RSA_private_decrypt(red, (unsigned char*)msg, (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);
}
fwrite(decrypt, 1, strlen(decrypt), out);
if(feof(in))
{
break;
}
}
fclose(in);
fclose(out);
RSA_free(keypair);
return 0;
}
When I run code it gives me back error saying:Error decrypting message: error:0407A079:rsa routines:RSA_padding_check_PKCS1_OAEP:oaep decoding error Sorry if my question sound silly. Hope you can help. Thanks.
There are a few errors here. First when you're reading and encrypting:
red = fread(msg, 1, RSA_size(keypair)-42, in);
if((RSA_public_encrypt(RSA_size(keypair)-42, (unsigned char*)msg, (unsigned char*)encrypt,
keypair, RSA_PKCS1_OAEP_PADDING)) == -1) {
A call to fread won't necessarily read the number of bytes asked for, and could return 0. So when you reach the end of the file, you man be encrypting more bytes than you need. So pass in red for the number of bytes to encrypt. Also, first check if red is 0 and if so break out of the loop:
red = fread(msg, 1, RSA_size(keypair)-42, in);
if (red == 0) break;
if(((red=RSA_public_encrypt(RSA_size(keypair)-42, (unsigned char*)msg, (unsigned char*)encrypt,
keypair, RSA_PKCS1_OAEP_PADDING))) == -1) {
Note that we're saving the return value of RSA_public_encrypt. That comes into play here where you're writing the encrypted data to disk:
if(fwrite(encrypt, 1, strlen(encrypt), out) == 1)
encrypt is an array of characters, not a string. This means it's not NULL terminated, and it might contain NULL bytes. So you can't use strlen. Instead, capture the return value of RSA_public_encrypt and pass that as the size to write:
if(fwrite(encrypt, 1, red, out) == 1)
Because we're checking the return value of fread to break out of the loop, this isn't needed:
if(feof(in))
{
break;
}
See this post regarding the perils of using feof.
Then there's this when you're reading back the encrypted data:
red = fread(msg, 1, 256, in);
if(RSA_private_decrypt(red, (unsigned char*)msg, (unsigned char*)decrypt,
keypair, RSA_PKCS1_OAEP_PADDING) == -1) {
RSA_private_decrypt expects a single encrypted block whose length is RSA_size(keypair). So read in that many bytes from disk and pass in that many bytes to the function. Also, check the return value of fread and break out if you don't get the expected amount, and capture the return value of RSA_private_decrypt:
red = fread(msg, 1, RSA_size(keypair), in);
if (red < RSA_size(keypair)) break;
if((red=RSA_private_decrypt(red, (unsigned char*)msg, (unsigned char*)decrypt,
keypair, RSA_PKCS1_OAEP_PADDING)) == -1) {
Later when you write the decrypted data to disk:
fwrite(decrypt, 1, strlen(decrypt), out);
While what was decrypted is probably a string (if your input file was plain text), the returned data is not NULL terminated, so explicitly write than many bytes instead of using strlen:
fwrite(decrypt, 1, red, out);
Finally, as with the encryption loop, this is not needed in the decryption loop:
if(feof(in))
{
break;
}
With these fixes applied, you should get the expected results.
I'm new with cryptography, so I decided to create simple program that would open a file encrypt data, put it in etest.txt, then open this file decrypt it and put it indetest.txt. I know it sounds really weired but its for educational purposes. so here is my code.
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <stdio.h>
#include <string.h>
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 = malloc(256); // Message to encrypt
char *encrypt = NULL; // Encrypted message
char *decrypt = NULL; // Decrypted message
char *err; // Buffer for any error messages
// Generate key pair
RSA *keypair = RSA_generate_key(2048, 3, NULL, NULL);
FILE *in = fopen("test.txt", "rb");
FILE *out = fopen("etest.txt", "wb");
if(in == NULL)
{
printf("in Error is %d (%s).\n", errno, strerror(errno));
}
if(out == NULL)
{
printf("out Error is %d (%s).\n", errno, strerror(errno));
}
encrypt = malloc(RSA_size(keypair));
for(;;)
{
//213 because of padding
memset(msg, '\0', 256);
memset(encrypt, '\0', 256);
fread(msg, 213, 1, in);
if((RSA_public_encrypt(strlen(msg), (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);
}
if(fwrite(encrypt, 256, 1, out) != 1)
{
printf("fwrite Error is %d (%s).\n", errno, strerror(errno));
}
if(feof(in))
{
break;
}
}
fclose(in);
fclose(out);
in = fopen("etest.txt", "rb");
out = fopen("dtest.txt", "wb");
if(in == NULL)
{
printf("in Error is %d (%s).\n", errno, strerror(errno));
}
if(out == NULL)
{
printf("out Error is %d (%s).\n", errno, strerror(errno));
}
decrypt = malloc(RSA_size(keypair));
for(;;)
{
//I use malloc because if i didnt it would from file and if it filled the msg and if this function would execute second time it would not overwrite the whole buffer and would cause problem
memset(decrypt, '\0', 256);
memset(msg, '\0', 256);
fread(msg, 256, 1, in);
if(RSA_private_decrypt(256, (unsigned char*)msg, (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);
}
fwrite(decrypt, 256, 1, out);
if(feof(in))
{
break;
}
}
fclose(in);
fclose(out);
RSA_free(keypair);
return 0;
}
When I run code it gives me back error saying:Error decrypting message: error:0407A079:rsa routines:RSA_padding_check_PKCS1_OAEP:oaep decoding error but if i delete this codememset(msg, '\0', 256); it shows that everything works fine but it causes problems because msg buffer is overwritten with first few bytes that second fread() function overwrote.
Sorry if my questions sound silly. Hope you can help. thanks.
Your are using fwrite(decrypt, 256, 1, out); which is wrong.size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) Second parameter is the size in bytes of each element to be read And the third one is number of elements, each one with a size of size bytes.