Memory error - Simple XOR encryption in C - c

I am having some memory issues with printing hex in the following format: \xAA\xAB\xDC using my encryption routine.
I did some modifications, using snprintf() and strcat() in an attempt to fix the output and it worked to some degree.
This is the function I originally started out with, which is probably better than my modified version.
char *encrypt(char key, const char *a) {
char *output = malloc(strlen(a)+1);
bzero(output, strlen(a)+1);
strcpy(output, a);
char *tmp = output;
int i;
for (i = 0; tmp[i] != 0; i++) {
tmp[i] = key ^ tmp[i];
}
return output;
}
My current progress is as follows:
char *encrypt(char key, const char *a)
{
char buf[256];
char *tmp = a;
int i;
int *k;
for (i = 0; tmp[i] != 0; i++)
{
char temp[10];
k = key ^ tmp[i];
snprintf(temp, sizeof(temp), "\\x%s", k);
strcat(buf, temp);
}
return buf;
}
int main(int argc, char **argv)
{
if (argv[1] == NULL){
printf("Usage: %s <string>\n", argv[0]);
}
else printf("Encrypted string: %s\n", encrypt(0xEB, argv[1]));
return 0;
}
If anyone could point me in the right direction on how to fix the memory issue, and if the code can be improved I would appreciate that a lot.

The primary issue, in your code, buf is local to the function encrypt(). So you may not return the array from the function. Once the function finishes, the array will cease to exist and the returned address will be invalid. If the returned value is ued in the caller, it will invoke undefined behavior.
You need to define buf as a pointer and allocate dynamic memory using malloc() or family. Also, you need to free() the memory, once the usage is over.
That said,
you have defined k to be a pointer but did not allocate memory to it.
k = key ^ tmp[i]; seems meaningless, maybe you meant *k = key ^ tmp[i];
%s expects a pointer to char array (null-terminated) as argument. From that point, snprintf(temp, sizeof(temp), "\\x%s", k); also looks wrong. What you need is snprintf(temp, sizeof(temp), "\\x%d", *k); to print the int value.

Instead of:
int *k;
k = key ^ tmp[i];
snprintf(temp, sizeof(temp), "\\x%s", k);
use this:
unsigned char k;
k = key ^ tmp[i];
snprintf(temp, sizeof temp, "\\x%02X", k);
Note that you also have other changes to make regarding buf. Firstly you never initialize it, so you are appending to junk. And you never check that you didn't overflow it.
Also you attempt to return this from a function, however, since it is a local variable, it ceases to exist when the function returns.
See this thread for some suggestions of how to get freshly-written string out of a function. You could use malloc(256) in the same vein as your first attempt (and remember to replace sizeof buf with the mallocated length, in the snprintf call).
It'd be more robust to use unsigned char instead of char for both the key and the message. An example of the issues is that on x86 or x64, char has a range of -128 to 127 so when you supply 0xEB (i.e. 235) this is an out-of-range assignment which is not well-defined.
But on common systems you will get away with using char because they tend to define out-of-range assignment by using 2's complement and truncating excess bits, which works in your situation.

Related

confusion about printf() in C

I'm trying to hexdump a file with following code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define SIZE 16
void pre_process(char buffer[],int len);
int main(int argc, char **argv){
if(argc == 2){
char *file = argv[1];
FILE *input = fopen(file,"r");
char buffer[SIZE];
char *tmp = malloc(4);
while(!feof(input)){
printf("%06X ",ftell(input)); /*print file pos*/
fread(buffer,1,SIZE,input); /*read 16 bytes with buffer*/
for (int i=0;i<SIZE;i += 4){ /*print each 4 bytes with hex in buffer*/
memcpy(tmp,buffer+i,4);
printf("%08X ",tmp);
}
printf("*");
pre_process(buffer,SIZE); /*print origin plain-text in buffer. subsitute unprint char with '*' */
printf("%s",buffer);
printf("*\n");
}
free(tmp);
fclose(input);
}
}
void pre_process(char buffer[],int len){
for (int i=0;i<len;i++){
if(isblank(buffer[i]) || !isprint(buffer[i]))
buffer[i] = '*';
}
}
reading a slice from lord of ring,result as below:
enter image description here
so, why the hex code are all the same ? It looks like something wrong with printf("%08X ",tmp);
thx for your help.
The answer lies here:
memcpy(tmp,buffer+i,4);
printf("%08X ",tmp);
memcpy as you might already be aware, copies 4 bytes from buffer+i to where tmp is pointing to.
Even though this is done in a loop, tmp continues to hold the address of a specific location, which is never changed. The contents at that address/location in memory are updated with every memcpy() call.
In a nutshell, the house remains there only, hence the address remains the same but people change places, new people arrive as older ones are wiped out!
Also, there is plenty to improve/fix here. I recommend starting with enabling warnings by -Wall option with your compiler.
tmp stores the address of a buffer; that address never changes. What you want to print is the contents of the buffer that tmp points to. In this case, tmp point to a buffer of 4 chars; if you write
printf( "%08X ", *tmp );
you’ll only print the value of the first element - since tmp has type char *, the expression *tmp has type char and is equivalent to writing tmp[0].
To treat what’s in those bytes as an unsigned int (which is what the %X conversion specifier expects), you need to cast the pointer to the correct type before dereferencing it:
printf( "%08X ", *(unsigned int *) tmp );
We first have to cast tmp from char * to unsigned int *, then dereference the result to get the unsigned int equivalent of those four bytes.
This assumes sizeof (unsigned int) == 4 on your system - to be safe, you should write your malloc call as
char *tmp = malloc( sizeof (unsigned int) );
and
for ( int i = 0; i < SIZE; i += sizeof (unsigned int) )
{
memcpy( tmp, buffer + i, sizeof (unsigned int) );
...
}
instead.
You should not use feof as your loop condition - it won’t return true until after you try to read past the end of the file, so your loop will execute once too often. You’ll want to look at the return value of fread to determine whether you’ve reached the end of the file.

How can I implement a function to concatenate to a char* and not char array?

How can I implement a function that will concatenate something to a char* (not char array)?
Example of what I want:
#include <stdio.h>
#include <string.h>
int main() {
char* current_line;
char temp[1];
sprintf(temp, "%c", 'A');
// This causes a seg fault. I of course don't want that, so how do I get this to work properly?
strcat(current_line, temp);
return 0;
}
How can I fix this to work properly (and please, tell me if I need to add anything to my question or point me in the right direction because I couldn't find anything)?
Edit: I made this but it seg faults
char* charpointercat(char* mystr, char* toconcat) {
char ret[strlen(mystr) + 1];
for(int i = 0; mystr[i] != '\0'; i++) {
ret[i] = mystr[i];
}
return ret;
}
You have 3 problems:
You do not allocate memory for current_line at all!
You do not allocate enough memory for temp.
You return a pointer to a local variable from charpointercat.
The first one should be obvious, and was explained in comments:
char *current_line only holds a pointer to some bytes, but you need to allocate actual bytes if you want to store something with a function like stracat.
For the secoond one, note that sprintf(temp, "%c", 'A'); needs at least char temp[2] as it will use one byte for the "A", and one byte for terminating null character.
Since sprintf does not know how big temp is, it writes beyond it and that is how you get the segfault.
As for your charpointercat once the function exits, ret no longer exists.
To be more precise:
An array in C is represented by a pointer (a memory address) of its first item (cell).
So, the line return ret; does not return a copy of all the bytes in ret but only a pointer to the first byte.
But that memory address is only valid inside charpointercat function.
Once you try to use it outside, it is "undefined behavior", so anything can happen, including segfault.
There are two ways to fix this:
Learn how to use malloc and allocate memory on the heap.
Pass in a third array to the function so it can store the result there (same way you do with sprintf).
From the first code you posted it seems like you want to concatenate a char to the end of a string... This code will return a new string that consists of the first one followed by the second, it wont change the parameter.
char* charpointercat(char* mystr, char toconcat) {
char *ret = (char*) malloc(sizeof(char)*(strlen(mystr) + 2));
int i;
for(i = 0; mystr[i] != '\0'; i++) {
ret[i] = mystr[i];
}
ret[i] = toconcat;
ret[i + 1] = '\0';
return ret;
}
This should work:
char* charpointercat(char* mystr, char* toconcat) {
size_t l1,l2;
//Get lengths of strings
l1=strlen(mystr);
l2=strlen(toconcat);
//Allocate enough memory for both
char * ret=malloc(l1+l2+1);
strcpy(ret,mystr);
strcat(ret,toconcat);
//Add null terminator
ret[l1+l2]='\0';
return ret;
}
int main(){
char * p=charpointercat("Hello","World");
printf("%s",p);
//Free the memory
free(p);
}

Capitalizing all copies of a word: why does this code fail when it's in its own function?

I have two C-style strings:
char st[100] = "to be or not to be ";
char sub_s[100] = "be";
I need to find the beginning of the "be" with strstr(st, sub_s) and change it to capital letters. The new string needs to be `"to BE or not to BE ";
I manage to do it with out the function like so:
void main()
{
char st[100] = "to be or not to be ";
char sub_s[100] = "be";
char* p;
int i;
while (p = strstr(st, sub_s))
{
for (i = 0; i < strlen(sub_s); i++)
{
p[i] -= 32;
}
}
printf("%s\n", st);
}
But when I put this code into its own function it doesn't work any more:
void main()
{
char st[100] = "to be or not to be ";
char sub_s[100] = "be";
replaceSubstring(st, sub_s);
}
void replaceSubstring(char* str, char* substr)
{
int* p;
int i;
while (p = strstr(str, substr))
{
for (i = 0; i < strlen(substr); i++)
{
p[i] -= 32;
}
}
printf("%s\n", st);
}
What's going on here?
In the function that you've written, you've set the type of p to be an int*, not a char *. This means when you write
p[i] -= 32;
the compiler will assume each element pointed at by p is an int and therefore take a step of size sizeof(int) in memory rather than a step of size 1 in memory. In other words, the code is interpreted as
Start at the location pointed at by p.
Jump forward i * sizeof(int) bytes.
Read an integer value from that location.
Subtract 32 from it.
Write it back
rather than
Start at the location pointed at by p.
Find the character i steps down from there.
Subtract 32 from that character.
To fix this, change the type of p to be char*, not int*.
This is the sort of error that would likely be easily detected if you cranked the compiler warning level up to maximum. I would strongly recommend doing that when you're learning to code, then asking questions about the warnings you get when you don't understand them.
Some other stray notes:
The return type of main should be int, not void.
Rather than subtracting 32 from each character, which works but isn't the clearest thing in the word, consider using the tolower function from the <ctype.h> header.
If the substring you're searching for consists solely of non-letter characters (say, ":-)"), then this code can cause an infinite loop. Do you see why? Think about how you might fix it.

Int to char array as a function returning an array of char the simple way

I have been looking on internet for this and so far i just found a lot of questions for specific answer and not a general one.
i am kind of rusty on C. And i want to make a function that will return an array of char.
this is what i got and is not working. basically a way to convert a byte array to an array of chars to do atoi later..
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char *get_char(int my_byte[], int packetsize)
{
char *array_char=(char *) malloc(sizeof(char)*10); //trying this but didnt work
// char array_char[10]; //i had it like this before(was told to do it)
for(int i=0;i<10;i++)
{
array_char[i]=my_byte[i]+0;
}
return array_char;
}
int main()
{
int byte_array[]={1,2,3,4,5,6,7,8,9,0};
char *temp;
char data;
temp=get_char(byte_array,10);
data=*temp;
printf("String point %s ",data);
}
Two fixes:
As you want to convert to char, then
array_char[i]=my_byte[i]+0; should be array_char[i]=my_byte[i]+'0'; Note '0' is character (that will be converted to int) instead of numeric 0 (which doesn't do anything).
Also you must free temp pointer in main as that memory is dynamically allocated in get_char() function.
Edit: just notice another issue in your get_char()
char *array_char=(char *) malloc(sizeof(char)*10);
should be
char *array_char= malloc(sizeof(char)*(packetsize+1));
After the for loop, ensure the buffer is NUL-terminated:
array_char[packetsize] = '\0';
Notice that your packetsize is never used - you should get some compiler warning about it. It's bad to hard code 10 in your malloc - it's actually the whole idea of parsing the packetsize as a parameter - so use it properly.
You need to watch out for these things:
You need to add a null-terminating character at the end of *array_char, otherwise using this pointer allocated from the heap will cause undefined behaviour.
You can simply allocate *array_char like this:
char *array_char = malloc(packetsize+1);
As sizeof(char) is 1, and +1 for trailing nullbyte.
You also don't need to cast return of malloc().
Instead of passing 10 as packetsize to get_char(), you should pass this size as sizeof(arr) / sizeof(arr[0], which is the calculated size of the array. This can be a size_t variable declared somewhere or even a macro.
malloc() needs to be checked, as it can return NULL if unsuccessful.
You need to free() temp at some point in the program.
array_char[i]=my_byte[i]+0; needs to be array_char[i]=my_byte[i]+'0'; instead, as '0' is the ascii code for a zero character.
char data needs to be char *data, as temp is a pointer.
If you compile with -Wall -Wextra, you will see that this line:
data=*temp;
Is dangerous, and will trigger warnings of making pointers from integers without a cast. It will most likely lead to a segmentation fault. If temp and data are both pointers, then you can simply use:
data=temp;
Which sets data to the address of temp. Sometimes this is written as data = &(*temp);, but this is harder to read. Although their is no need for data, and using temp alone should be fine.
Your code can then look like this:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define ARRAYSIZE(arr) (sizeof(arr) / sizeof(arr[0]))
char *get_char(int my_byte[], size_t packetsize) {
char *array_char = malloc(packetsize+1);
const char ascii = '0';
size_t i;
if (!array_char) {
printf("Cannot allocate %zu bytes\n", packetsize+1);
exit(EXIT_FAILURE);
}
for(i = 0; i < packetsize; i++) {
array_char[i] = my_byte[i] + ascii;
}
array_char[i] = '\0'; /* or array_char[packetsize] = '\0' */
return array_char;
}
int main(void) {
int byte_array[]={1,2,3,4,5,6,7,8,9,0};
char *temp, *data;
temp = get_char(byte_array, ARRAYSIZE(byte_array));
data = temp;
printf("String point %s\n", data);
printf("String converted into number = %d\n", atoi(data));
free(temp);
temp = NULL;
return 0;
}
You can also look into strtol, which is better than using atoi() in terms of error checking.
It is Not Wise Idea to Return a Array From A Function. So how to return a string then? As most of libc functions use we can use some thing like that (i.e) passing a buffer along with our input and expect function to use output buffer to give us result.
Some issue to take care while coding
write your logic first.
try to use available functions from libc.
while dealing with byte data/binary data be take precaution of buffer overflow.
don't allocate in a function and de-allocate in another function.
Below is Example of your code with modification.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <stdint.h>
int get_char(uint8_t my_byte[], int packetsize, char *buffer, int max_buffer)
{
int byte_itr, buf_itr;
char temp_buf[16]={0x00};
for(byte_itr=0, buf_itr=0; byte_itr<packetsize && max_buffer > buf_itr; byte_itr++)
{
memset(temp_buf, 0x00, sizeof(temp_buf));
char temp_ch = my_byte[byte_itr];
snprintf(temp_buf, sizeof(temp_buf), "%d", temp_ch);
if( buf_itr+strlen(temp_buf) >=max_buffer){
break;
}else{
buf_itr += strlen(temp_buf);
strcat(buffer, temp_buf);
if(byte_itr+1 < packetsize){
strcat(buffer, ",");
buf_itr += 1;
}
}
}
return buf_itr;
}
int main()
{
uint8_t byte_array[]={1,2,3,4,5,6,7,8,9,0};
char char_array[32]={0x00};
int len = get_char(byte_array, 10, char_array, sizeof(char_array));
printf("String point %s : len %d\n", char_array, len);
}
NOTE:
when length return and size of output buffer same then buffer full condition happened.

Double Pointer and Char

I have a problem with the set_ccs function. I cannot take elements from user. How can i fix that?
int main(){
char *ccs;
*ccs =(char*)malloc(sizeof(char) * 80);//i have to use dynamic memory allocation
printf("Enter CCS: ");
set_ccs(&ccs);
free(ccs);
return 0;
}
int set_ccs(char **ccs){
int i = 0;
scanf("%s",*ccs);//Is it better to use fgets? Because scanf seems to count 'enter'
while(*ccs!='\0'){
ccs++;
i++;
}
printf("Length of sequence : %d\n",i);//It always return 3
printf("%s",ccs); //with weird elements
return i;
}
Thanks already.
In addition to unwinds answer that you should just use
char *ccs;
ccs = malloc(80);
You should make the function set_ccs() accept a pointer:
int set_ccs(char *ccs)
And call it like this from your main:
set_ccs(css);
Then in your function you can use scanf() like so:
scanf("%s", css);
Now you if you want to check for '\0', it is good practice to initialize your "string" to 0 before you use it. You can do that with calloc(80) instead of malloc(80).
If you need to have the pointer to pointer (char **ccs), you have to make a double pointer in your main, check this code:
int main(){
char *ccs;
char **ccs2; //a pointer to a pointer
ccs = calloc(80); //i have to use dynamic memory allocation
ccs2 = &ccs; //pass the address of the pointer to the double pointer
printf("Enter CCS: ");
set_ccs(ccs2); //pass the double pointer
free(ccs);
return 0;
}
int set_ccs(char **ccs){
int i = 0;
scanf("%s", *ccs);
char *c = *ccs; //copy to make increments
while(*c != '\0'){
c++;
i++;
}
printf("Length of sequence : %d\n", i);
printf("%s", *ccs);
return i;
}
This:
char *ccs;
*ccs =(char*)malloc(sizeof(char) * 80);
Is wrong, and there is no sane compiler that will accept it. You're shoving a pointer into a char, and it certainly won't fit.
It should just be:
ccs = malloc(80);
There's no need to scale by sizeof (char), that is always 1.
Also, please don't cast the return value of malloc() in C.

Resources