Whenever I try to base64 decode files (using OpenSSL's BIO_f_base64()) larger than 8192, I always seem to get some wrong value.
What is with this magic number 8192? Any help to educate me is greatly appreciated!
UPDATED:
Here is part of my code:
int dgst(char *alg)
{
EVP_MD_CTX ctx;
const EVP_MD *md;
unsigned char md_value[EVP_MAX_MD_SIZE];
unsigned int md_len, i;
char *toB64val = NULL;
char *data = NULL;
OpenSSL_add_all_digests();
md = EVP_get_digestbyname(alg);
if(!md) {
printf("Unknown message digest %s\n", alg);
exit(1);
}
data = readFileBuffer("file_out");
printf("strlen(data) %d\n", strlen(data));
EVP_MD_CTX_init(&ctx);
EVP_DigestInit_ex(&ctx, md, NULL);
EVP_DigestUpdate(&ctx, data, strlen(data));
EVP_DigestFinal_ex(&ctx, md_value, &md_len); //retrieve digest from ctx unto md_value and #bytes written is copied into md_len
EVP_MD_CTX_cleanup(&ctx);
unsigned char *copy = malloc(md_len);
memcpy(copy, md_value, md_len);
char *buff = encbase64(copy, md_len);
printf("Digest is:%s\n ", buff);
free(buff);
free(toB64val);
free(data);
return 0;
}
char *readFileBuffer(char *name)
{
FILE *file;
char *buffer = NULL;
unsigned long fileLen;
//Open file
file = fopen(name, "rb");
if (!file)
{
fprintf(stderr, "Unable to open file %s", name);
return;
}
//Get file length
fseek(file, 0, SEEK_END);
fileLen=ftell(file);
printf("file length = %ld\n", fileLen);
fseek(file, 0, SEEK_SET);
//printf("Allocate memory\n");
buffer=(char *)malloc(fileLen+1);
printf("length of write buffer = %d\n", strlen(buffer));
if (!buffer)
{
fprintf(stderr, "Memory error!");
}
long int n = fread(buffer,1, fileLen,file);
buffer[n] = '\0';
printf("Read no. of bytes = %ld into buffer \n", n);
printf("len of buffer %d \n", strlen(buffer));
if (!buffer)
{
fprintf(stderr, "Memory error!");
fclose(file);
}
fclose(file);
return buffer;
}
char *encbase64( char *input, int length)
{
BIO *bmem, *b64;
BUF_MEM *bptr;
b64 = BIO_new(BIO_f_base64());
//BIO_set_flags(b64,BIO_FLAGS_BASE64_NO_NL);
bmem = BIO_new(BIO_s_mem());
b64 = BIO_push(b64, bmem);
BIO_write(b64, input, length);
BIO_flush(b64);
BIO_get_mem_ptr(b64, &bptr);
char *buff = (char *)malloc(bptr->length);
memcpy(buff, bptr->data, bptr->length-1);
buff[bptr->length-1] = 0;
BIO_free_all(b64);
return buff;
}
it doesn't seem to have any problems with 8k boundaries. could you show us soucecode how you call it?
update:
int dgst(char *alg)
{
EVP_MD_CTX ctx;
const EVP_MD *md;
unsigned char md_value[EVP_MAX_MD_SIZE];
unsigned int md_len, i;
char *toB64val = NULL;
char *data = NULL;
OpenSSL_add_all_digests();
md = EVP_get_digestbyname(alg);
if(!md) {
printf("Unknown message digest %s\n", alg);
exit(1);
}
data = readFileBuffer("file_out");
//printf("strlen(data) %d\n", strlen(data)); <- don't use strlen on binary data
EVP_MD_CTX_init(&ctx);
EVP_DigestInit_ex(&ctx, md, NULL);
EVP_DigestUpdate(&ctx, data, strlen(data));
EVP_DigestFinal_ex(&ctx, md_value, &md_len); //retrieve digest from ctx unto md_value and #bytes written is copied into md_len
EVP_MD_CTX_cleanup(&ctx);
unsigned char *copy = malloc(md_len);
memcpy(copy, md_value, md_len);
char *buff = encbase64(copy, md_len);
printf("Digest is:%s\n ", buff);
free(buff);
free(toB64val);
free(data);
return 0;
}
char *readFileBuffer(char *name)
{
FILE *file;
char *buffer = NULL;
unsigned long fileLen;
//Open file
file = fopen(name, "rb");
if (!file)
{
fprintf(stderr, "Unable to open file %s", name);
return;
}
//Get file length
fseek(file, 0, SEEK_END);
fileLen=ftell(file);
printf("file length = %ld\n", fileLen);
fseek(file, 0, SEEK_SET);
//printf("Allocate memory\n");
buffer=(char *)malloc(fileLen/*+1*/); // <- not a string - no need to +1
//printf("length of write buffer = %d\n", strlen(buffer)); <- again strlen on binary data (you just allocated it, so it contains random bytes)
if (!buffer)
{
fprintf(stderr, "Memory error!");
}
long int n = fread(buffer,1, fileLen,file);
//buffer[n] = '\0'; // not a string - no need to end it
printf("Read no. of bytes = %ld into buffer \n", n);
//printf("len of buffer %d \n", strlen(buffer)); <- buffer length is in 'n'
if (!buffer)
{
fprintf(stderr, "Memory error!");
fclose(file);
}
fclose(file);
return buffer;
}
char *encbase64( char *input, int length)
{
BIO *bmem, *b64;
BUF_MEM *bptr;
b64 = BIO_new(BIO_f_base64());
//BIO_set_flags(b64,BIO_FLAGS_BASE64_NO_NL);
bmem = BIO_new(BIO_s_mem());
b64 = BIO_push(b64, bmem);
BIO_write(b64, input, length);
BIO_flush(b64);
BIO_get_mem_ptr(b64, &bptr);
char *buff = (char *)malloc(bptr->length);
memcpy(buff, bptr->data, bptr->length/*-1*/); // removed '+1'
//buff[bptr->length-1] = 0; // not a string
BIO_free_all(b64);
return buff;
}
Related
I'm trying to setup a client and a server program where the client can download a file from the server.
I have got the client to download a .txt file however, the .txt file is only created, none of the data within it is transferred.
I've figured out the error is either from when the server sends the size of the file to the client OR the client is failing to recognize where the EOF is.
This is my server side code:
int send_all(int clientSocket, const void *buffer, int len) {
const char *pbuf = (const char *) buffer;
while(len > 0) {
int sent = send(clientSocket, pbuf, len, 0);
printf("%d\n", sent);
if(sent < 1) {
printf("%s\n", "Can't write to socket");
return -1;
}
pbuf += sent;
len -= sent;
}
return(0);
}
void SendFileToClient(int clientSocket, char* fileName) {
//int offset;
char buffer[0x1000];
char temp[512] = "/root/Documents/";
const char* filename = fileName;
struct stat s;
strcat(temp, filename);
printf("%s\n", temp);
//append the filenameonto the directory
if(stat(temp, &s) == -1) {
printf("%s\n", "Can't get file info");
return;
}
FILE *file = fopen(temp, "rb");
if(!file) {
printf("%s\n", "Can't open the file for reading");
return;
}
off_t size = s.st_size;
off_t tmp_size = ntohl(size);
if(send_all(clientSocket, &tmp_size, sizeof(tmp_size)) == 0) {
while(size > 0) {
printf("%ld\n", size);
int rval = fread(buffer, 1, min(sizeof(buffer), size), file);
if(rval < 1) {
printf("%s\n", "Cant read from file");
break;
}
if (send_all(clientSocket, buffer, rval) == -1)
break;
size -= rval;
}
}
fclose(file);
}
This is my client side code:
int write_all(FILE *file, const void *buffer, int len) {
const char *pbuf = (const char *) buffer;
while (len > 0) {
int written = fwrite(pbuf, 1, len, file);
if(written < 1) {
printf("%s\n", "Cant write to file");
return -1;
}
pbuf += written;
len -= written;
}
return 0;
}
int read_all(int clientSocket, void *buffer, int len) {
char *pbuf = (char *) buffer;
int total = 0;
while (len > 0) {
int rval = recv(clientSocket, pbuf, len, 0);
if(rval < 0) {
printf("%s\n", "Cant read from socket");
return -1;
}
if(rval == 0) {
printf("%s\n", "Socket disconnected");
return 0;
}
pbuf += rval;
len -= rval;
total += rval;
}
return total;
}
void RecvFile(int clientSocket, const char* filename) {
int rval;
char buffer[0x1000];
//printf("%s\n", filename);
FILE *file = fopen(filename, "wb");
if(!file) {
printf("%s\n", "Cant open file for writing");
return;
}
off_t size = 0;
//this statement is not working
if(read_all(clientSocket, &size, sizeof(size)) == 1) {
size = ntohl(size);
printf("%s%ld\n", "size: ", size);
while(size > 0) {
rval = read_all(clientSocket, buffer, min(sizeof(buffer), size));
printf("%s%d\n", "rval: ", rval);
if(rval < 1)
break;
if(write_all(file, buffer, rval) == -1) {
printf("%s\n", "Cant write to file");
break;
}
}
}
printf("%s\n", "closing file...");
fclose(file);
}
My apologies if the code looks a bit messy - for some reason it didn't paste in with nice formatting.
I believe this is where part of the problem is, but even through various debugging I can't seem to get it to work :(
//this statement is not working
if(read_all(clientSocket, &size, sizeof(size)) == 1) {
Thanks in advance for any help!
For my following code, I expect to have an error message when the arguments are less than 3 while whether I typed in
./compress_uncompress -c compressedimg1 > image.bmp
or
./compress_uncompress -c compressedimg1
or
./compress_uncompress -c
I always get "couldn't open input file". Also, for
./compress_uncompress -e compressedimg1 > image.bmp
I expect to get error message of "invalid argv[1]" while I got it successfully decompressed without any error message.
unsigned long (*compressBound)(unsigned long length);
int (*compress)(void *dest, unsigned long* destLen, const void* source, unsigned long sourceLen);
int (*uncompress)(void *dest, unsigned long* destLen, const void* source, unsigned long sourceLen);
void error_exit(const char *error_message)
{
printf("Error: %s\n", error_message);
exit(1);
}
int main(int argc, const char* argv[]){
FILE *fp;
unsigned long uncompressed_size;
unsigned long compressed_size;
char* uncompressed_buffer;
char* compressed_buffer;
int compress_result;
int uncompress_result;
void* lib = dlopen("libz.so", RTLD_NOW);
if(lib == NULL)
{
error_exit("couldn’t open libz.so");
}
compressBound = dlsym(lib, "compressBound");
if(compressBound == NULL)
{
error_exit("compress bound is null!");
}
compress = dlsym(lib, "compress");
if(compress == NULL)
{
error_exit("couldn't load the compress symbol from zlib");
}
uncompress = dlsym(lib, "uncompress");
if(uncompress == NULL)
{
error_exit("couldn't load the uncompress symbol from zlib");
}
fp = fopen(argv[2], "rb");
if(fp == NULL){
error_exit("couldn’t open input file");
}
if(argc < 3){
error_exit("too few program arguments");
}
if(strcmp(argv[1],"-c") == 0){
fseek(fp, 0, SEEK_END); //to the end of the file
uncompressed_size = ftell(fp); //find the size of the uncompressed file
fseek(fp, 0, SEEK_SET); //back to the begining
uncompressed_buffer = malloc(uncompressed_size + 1);
fread(uncompressed_buffer, uncompressed_size, 1, fp);
compressed_size = compressBound(uncompressed_size);
compressed_buffer = malloc(compressed_size);
compress_result = compress(compressed_buffer, &compressed_size, uncompressed_buffer, uncompressed_size);
if(compress_result < 0){
error_exit("compress failed");
}
fwrite(&uncompressed_size, sizeof(unsigned long), 1, stdout);
fwrite(&compressed_size, sizeof(unsigned long), 1, stdout);
fwrite(compressed_buffer, compressed_size, 1, stdout);
} else if(strcmp(argv[1],"-d") == 0){
fread(&uncompressed_size, sizeof(unsigned long), 1, fp);
fread(&compressed_size, sizeof(unsigned long), 1, fp);
compressed_buffer = malloc(compressed_size);
fread(compressed_buffer, compressed_size, 1, fp);
uncompressed_buffer = malloc(uncompressed_size);
uncompress_result = uncompress(uncompressed_buffer, &uncompressed_size, compressed_buffer, compressed_size);
if(uncompress_result < 0){
error_exit("uncompress failed");
}
fwrite(uncompressed_buffer, uncompressed_size, 1, stdout);
} else{
error_exit("invalid argv[1]");
}
free(uncompressed_buffer);
free(compressed_buffer);
fclose(fp);
return 0;
}
I want to encrypt/decrypt a long file with RSA (I know AES is better, but this is just for a comparison) in openssl/libcrypto. I am splitting the input file into blocks of size numBlocks = inputFileLength/maxlen+1 where maxlen = 200. I can successfully encode and decode in the same loop as follows:
for (int i = 0; i < chunks; i++)
{
int bytesDone = i * maxlen;
int remainingLen = inLength - bytesDone;
int thisLen;
if (remainingLen > maxlen)
{
thisLen = maxlen;
} else
{
thisLen = remainingLen;
}
if((encBytes=RSA_public_encrypt(thisLen, data + bytesDone, encryptdata + bytesDone,
rsa_public, RSA_PKCS1_PADDING)) == -1)
{
printf("error\n");
}
if((decBytes=RSA_private_decrypt(encBytes, encryptdata + bytesDone, decryptdata + bytesDone,
rsa_private, RSA_PKCS1_PADDING)) == -1)
{
printf("error\n");
}
}
However, I want to save the encoded buffer encryptdata in a binary file, reading the binary file back and decryption. I try to do this as follows:
for (int i = 0; i < chunks; i++)
{
int bytesDone = i * maxlen;
int remainingLen = inLength - bytesDone;
int thisLen;
if (remainingLen > maxlen)
{
thisLen = maxlen;
} else
{
thisLen = remainingLen;
}
if((encBytes=RSA_public_encrypt(thisLen, data + bytesDone, encryptdata + bytesDone,
rsa_public, RSA_PKCS1_PADDING)) == -1)
{
printf("error\n");
}
}
writeFile("encoded.bin",encryptdata,strlen(encryptdata));
size_t size;
unsigned char *readData = readFile("encoded.bin", size);
int inputlen = size;
for (int i = 0; (i * keylen) < inputlen; i++) //keylen = 256
{
int bytesDone = i * keylen;
if((decBytes=RSA_private_decrypt(encBytes, readData + bytesDone, decryptdata + bytesDone,
rsa_private, RSA_PKCS1_PADDING)) == -1)
{
printf("error\n");
}
}
printf("Decrypted text: %s",decryptdata);
The readFile and writeFile functions are as follows:
void writeFile(char *filename, unsigned char *file, size_t fileLength
{
FILE *fd = fopen(filename, "wb");
if(fd == NULL) {
fprintf(stderr, "Failed to open file: %s\n", strerror(errno));
exit(1);
}
size_t bytesWritten = fwrite(file, 1, fileLength, fd);
if(bytesWritten != fileLength) {
fprintf(stderr, "Failed to write file\n");
exit(1);
}
fclose(fd);
}
unsigned char* readFile(char *filename, size_t size) {
FILE *fd = fopen(filename, "rb");
if(fd == NULL) {
fprintf(stderr, "Failed to open file: %s\n", strerror(errno));
exit(1);
}
// Determine size of the file
fseek(fd, 0, SEEK_END);
size_t fileLength = ftell(fd);
fseek(fd, 0, SEEK_SET);
size = fileLength;
// Allocate space for the file
unsigned char* buffer = (unsigned char*)malloc(fileLength);
// Read the file into the buffer
size_t bytesRead = fread(buffer, 1, fileLength, fd);
if(bytesRead != fileLength) {
fprintf(stderr, "Error reading file\n");
exit(1);
}
fclose(fd);
return buffer;
}
However, the decryption fails with the error message segmentation fault (core dump) and the decrypt function only returns -1 for every block. Any help will be appreciated.
ReadFile modifies the parameter "size" which is passed by value, thus when the readfile function returns, size is not affected.
I would change readfile proto as follows :
unsigned char* readFile(char *filename, size_t *size)
and then change the call into
unsigned char *readData = readFile("encoded.bin", &size);
and finally modify the readFile size update to
size = fileLength;
Your have various technical errors in your code like doing a strlen(..) on binary data in this statement:
writeFile("encoded.bin",encryptdata,strlen(encryptdata));
encryptdata is binary data that can include 0 that would be interprited as a string termination by strlen(..)
But the main problem is that you try to use RSA as a block cipher. Your encrypted blocks are bigger that what you encrypt, but you don't handle that in your code. You might be able to get your code to handle this, but the right approach is to use ciphers invented for bulk encryption, like AES. When you do that, you automatically get support for 'blocking' out of the box.
In addition to this you get something like a factor 1000 faster encryption.
I want to send through a socket a message encrypted in symmetric way with his hash.
If possible i want to do all with only one read on the file to be more efficient and sending data when they are ready.
I make this but i can't figure out why doesn't work:
void symmetric_encrypt_send(SSL* connection, char* file_name, unsigned char* key, int key_len){
//generic
int ret;
unsigned char buffer[DIM_BUFFER];
FILE* fd;
int readed_byte;
//encrypt
EVP_CIPHER_CTX* ctx;
unsigned char ciphertex[DIM_BUFFER];
int outlen = 0;
//hash
EVP_MD_CTX sha_ctx;
unsigned int digest_size = 32;
unsigned char hash[digest_size];
//open file
fd = fopen(file_name, "r");
if(fd == NULL){
printf("Impossible to open %s file\n", file_name);
exit(EXIT_FAILURE);
}
//encrypt initialization
ctx = (EVP_CIPHER_CTX*)malloc(sizeof(EVP_CIPHER_CTX));
EVP_CIPHER_CTX_init(ctx);
EVP_EncryptInit(ctx, SYM_CIPHER, key, NULL);
//hash initialization
EVP_MD_CTX_init(&sha_ctx);
EVP_DigestInit(&sha_ctx, EVP_sha256());
//send dimension
struct stat st;
stat(file_name, &st); // file size = st.st_size
int tmp = ((st.st_size + digest_size)/ EVP_CIPHER_block_size(SYM_CIPHER)) + 1;
ret = secure_write(0, &tmp, sizeof(int), connection);
check_ret(ret, sizeof(int));
//read until end of file
//for each read update encrypt and hash
while( 1 ){
readed_byte = fread(buffer, sizeof(char), DIM_BUFFER, fd);
if(readed_byte == -1){
printf("Error");
exit(EXIT_FAILURE);
}
if(readed_byte == 0){ //nel caso in cui la dimensione del file è multipla di dim_buffer
break;
}
//Encrypt Update
EVP_EncryptUpdate(ctx, ciphertex, &outlen, buffer, readed_byte);
//hash update
EVP_DigestUpdate(&sha_ctx, buffer, readed_byte);
//send encrypted data at this step
printf("testo inviato: %.*s\n", outlen, ciphertex);
ret = secure_write(0, ciphertex, outlen, connection);
check_ret(ret, outlen);
if(readed_byte != DIM_BUFFER){
break;
}
}
//hashfinal; also clear ctx
EVP_DigestFinal(&sha_ctx, hash, &digest_size);
//encrypt update the hash
EVP_EncryptUpdate(ctx, ciphertex, &outlen, hash, digest_size);
ret = secure_write(0, ciphertex, outlen, connection);
check_ret(ret, outlen);
//EVP_EncryptFinal(); also close ctx so no need for EVP_CIPHER_CTX_cleanup(ctx);
ret = EVP_EncryptFinal(ctx, ciphertex, &outlen);
if(ret == 0)
exit(EXIT_FAILURE);
ret = secure_write(0, ciphertex, outlen, connection);
check_ret(ret, outlen);
//close
free(ctx);
fclose(fd);
}
where
#define DIM_BUFFER 1024
int secure_read(int fd, void* buffer, int count, SSL* sock);
int secure_write(int fd, void* buffer, int count, SSL* sock);
I'm trying to write encrypted data to a file. However, when reading it back into the program and trying to decrypt it, I only get garbage back out. Without writing it to a file it seems to work.. What am I doing wrong?
Here's the code:
MCRYPT td, td2;
char * string = "My secret message";
int i;
char *key; /* created using mcrypt_gen_key */
char *IV;
char * block_buffer;
int blocksize;
int keysize = 32; /* 192 bits == 24 bytes */
key = calloc(1, keysize);
strcpy(key, "This-is-my-key#########");
td = mcrypt_module_open("saferplus", NULL, "cbc", NULL);
td2 = mcrypt_module_open("saferplus", NULL, "cbc", NULL);
blocksize = mcrypt_enc_get_block_size(td);
block_buffer = malloc(blocksize);
IV=malloc(mcrypt_enc_get_iv_size(td));
for (i=0; i < mcrypt_enc_get_iv_size(td); i++) {
IV[i]=rand();
}
mcrypt_generic_init(td, key, keysize, IV);
mcrypt_generic_init(td2, key, keysize, IV);
strcpy(block_buffer, string);
printf("1: %s\n", block_buffer);
mcrypt_generic (td, block_buffer, blocksize);
FILE *myFile;
myFile = fopen("encrypted","ab");
fwrite(block_buffer, 1, blocksize, myFile);
fclose(myFile);
printf("2: %s\n", block_buffer);
myFile = fopen("encrypted","rb");
fread(block_buffer, 1, blocksize, myFile);
fclose(myFile);
printf("2.5: %s\n", block_buffer);
mdecrypt_generic (td2, block_buffer, blocksize);
printf("3: %s\n", block_buffer);
/* deinitialize the encryption thread */
mcrypt_generic_deinit (td);
mcrypt_generic_deinit(td2);
/* Unload the loaded module */
mcrypt_module_close(td);
mcrypt_module_close(td2);
return 0;
This works. I think you just needed to zero initialize block_buffer.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mcrypt.h>
int main()
{
MCRYPT td, td2;
char * string = "My secret message";
int i;
char *key; /* created using mcrypt_gen_key */
char *IV;
char * block_buffer;
int blocksize;
int keysize = 32; /* 192 bits == 24 bytes */
FILE *myFile;
key = calloc(1, keysize);
strcpy(key, "This-is-my-key#########");
td = mcrypt_module_open("saferplus", NULL, "cbc", NULL);
td2 = mcrypt_module_open("saferplus", NULL, "cbc", NULL);
blocksize = mcrypt_enc_get_block_size(td);
block_buffer = calloc(1, blocksize); /* Fixed issue here */
IV = malloc(mcrypt_enc_get_iv_size(td));
if ((block_buffer == NULL) || (IV == NULL)) {
fprintf(stderr, "Failed to allocate memory\n");
exit(EXIT_FAILURE);
}
for (i = 0; i < mcrypt_enc_get_iv_size(td); i++) {
IV[i] = rand();
}
mcrypt_generic_init(td, key, keysize, IV);
mcrypt_generic_init(td2, key, keysize, IV);
strcpy(block_buffer, string);
printf("1: %s\n", block_buffer);
mcrypt_generic (td, block_buffer, blocksize);
myFile = fopen("encrypted","w");
if ((myFile == NULL) || (fwrite(block_buffer, blocksize, 1, myFile) != 1)) {
fprintf(stderr, "Failed to write data\n");
exit(EXIT_FAILURE);
}
fclose(myFile);
printf("2: %s\n", block_buffer);
myFile = fopen("encrypted","r");
if ((myFile == NULL) || (fread(block_buffer, blocksize, 1, myFile) != 1)) {
fprintf(stderr, "Failed to read data\n");
exit(EXIT_FAILURE);
}
fclose(myFile);
printf("2.5: %s\n", block_buffer);
mdecrypt_generic (td2, block_buffer, blocksize);
printf("3: %s\n", block_buffer);
/* deinitialize the encryption thread */
mcrypt_generic_deinit (td);
mcrypt_generic_deinit(td2);
/* Unload the loaded module */
mcrypt_module_close(td);
mcrypt_module_close(td2);
return 0;
}