Last active
June 7, 2019 21:14
-
-
Save eanmos/00b33bae3bf6567dc6a1275cd69c14da to your computer and use it in GitHub Desktop.
Steganography
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef DSTRINGS_H | |
#define DSTRINGS_H | |
#include <math.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <stdlib.h> | |
#include <limits.h> | |
#include <assert.h> | |
#define DYNAMIC_STRING_GROW_FACTOR 1.5 | |
typedef struct DynamicString { | |
char *s; | |
size_t capacity; | |
size_t length; | |
} DynamicString; | |
void createDynamicString(DynamicString *, size_t); | |
void destroyDynamicString(DynamicString *); | |
void increaseDynamicStringCapacity(DynamicString *); | |
void appendCharToDynamicString(DynamicString *, char); | |
/* The CREATEDYNAMICSTRING function | |
* | |
* The function initializes a DynamicString passing by the first argument. | |
* The initial capacity of the string is passing by the second argument. | |
* Capacity is the max length of the string. At the same time length is | |
* current length of the string. Thus the function allocates capacity + 1 | |
* bytes for the string (considering the null-character). | |
* | |
* The input pointer to DynamicString struture should be a valid pointer and | |
* capacity should be greater than 0. | |
*/ | |
void createDynamicString(DynamicString *ret, size_t capacity) | |
{ | |
assert(ret); | |
assert(capacity > 0); | |
ret->s = malloc(capacity + 1); | |
assert(ret->s); | |
ret->length = 0; | |
ret->capacity = capacity; | |
} | |
/* The APPENDCHARTODYNAMICSTRING function | |
* | |
* The function appends a character to the input DynamicString. If capacity of | |
* the string is not enough the function increases it. | |
* | |
* The input pointer to a DynamicString should be a valid pointer as well as | |
* its string buffer. | |
*/ | |
void appendCharToDynamicString(DynamicString *s, char c) | |
{ | |
assert(s); | |
assert(s->s); | |
if (s->length == s->capacity) | |
increaseDynamicStringCapacity(s); | |
s->s[s->length++] = c; | |
s->s[s->length] = '\0'; | |
} | |
/* The INCREASEDYNAMICSTRINGCAPACITY function | |
* | |
* The function increases capacity of the input DynamicString. Grow factor | |
* is sets by a macro constant DYNAMIC_STRING_GROW_FACTOR. | |
* | |
* The input pointer to a DynamicString struture should be a valid pointer | |
* as well as its string buffer. | |
*/ | |
void increaseDynamicStringCapacity(DynamicString *s) | |
{ | |
assert(s); | |
assert(s->s); | |
const size_t newCapacity = ceil(s->capacity * DYNAMIC_STRING_GROW_FACTOR); | |
s->s = realloc(s->s, newCapacity + 1); | |
assert(s->s); | |
s->capacity = newCapacity; | |
} | |
/* The DESTROYDYNAMICSTRING function | |
* | |
* The function destroys the input DynamicString. It frees the string buffer | |
* of the input DynamicString. | |
* | |
* The input pointer to a DynamicString should be a valid pointer as well as | |
* its string buffer. | |
*/ | |
void destroyDynamicString(DynamicString *s) | |
{ | |
assert(s); | |
assert(s->s); | |
free(s->s); | |
} | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <limits.h> | |
#include <stdbool.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include "dstrings.h" | |
static bool hideMessage(FILE *, FILE *, const char *); | |
static int encodeBit(FILE *, FILE *, char); | |
static char *extractMessage(FILE *); | |
static bool extractChar(FILE *, char *); | |
static char *duplicateString(const char *); | |
int main(int argc, char *argv[]) | |
{ | |
if (argc < 2) { | |
fprintf(stderr, "Error: too few command line arguments. See how to use the program.\n"); | |
return EXIT_FAILURE; | |
} | |
if (!strcmp(argv[1], "--hide")) { | |
FILE *infile = fopen(argv[2], "r+"); | |
if (infile == NULL) { | |
fprintf(stderr, "Error: could not open input file \"%s\".\n", argv[1]); | |
return EXIT_FAILURE; | |
} | |
FILE *outfile = fopen(argv[3], "w+"); | |
if (outfile == NULL) { | |
fprintf(stderr, "Error: could not open output file \"%s\".\n", argv[2]); | |
return EXIT_FAILURE; | |
} | |
char *message = argv[4]; | |
if (hideMessage(infile, outfile, message) == true) | |
fprintf(stderr, "Info: the message was successfully hide.\n"); | |
fclose(infile); | |
fclose(outfile); | |
} else if (!strcmp(argv[1], "--extract")) { | |
FILE *infile = fopen(argv[2], "r+"); | |
if (infile == NULL) { | |
fprintf(stderr, "Error: could not open input file \"%s\".\n", argv[1]); | |
return EXIT_FAILURE; | |
} | |
char *extractedMsg = extractMessage(infile); | |
if (extractedMsg != NULL) { | |
printf("Message was successfully extracted: \"%s\".\n", extractedMsg); | |
free(extractedMsg); | |
} else { | |
fprintf(stderr, "Error: sorry, could not extract a message.\n"); | |
} | |
fclose(infile); | |
} else { | |
fprintf(stderr, "Error: too few command line arguments. See how to use the program.\n"); | |
return EXIT_FAILURE; | |
} | |
} | |
char *extractMessage(FILE *infile) | |
{ | |
DynamicString msgBuffer; | |
createDynamicString(&msgBuffer, 128); | |
char c; | |
while (extractChar(infile, &c) && c != '\0') | |
appendCharToDynamicString(&msgBuffer, c); | |
if (msgBuffer.length < 1) { | |
destroyDynamicString(&msgBuffer); | |
return NULL; | |
} | |
return duplicateString(msgBuffer.s); | |
} | |
bool extractChar(FILE *infile, char *ret) | |
{ | |
unsigned int extractedBits = 0; | |
*ret = 0; | |
for (int prev = 0, ch = fgetc(infile); ch != EOF; prev = ch, ch = fgetc(infile)) { | |
if (ch == '\n') { | |
*ret <<= 1; | |
*ret |= (prev == ' ') ? 1 : 0; | |
extractedBits++; | |
} | |
if (extractedBits == 8) | |
return true; | |
} | |
return false; | |
} | |
bool hideMessage(FILE *infile, FILE *outfile, const char *msg) | |
{ | |
for (; *msg; msg++) { | |
for (int mask = 0x80; mask; mask >>= 1) { | |
if (encodeBit(infile, outfile, *msg & mask) == EOF) { | |
fprintf(stderr, "Error: it's not enough lines in the input file.\n"); | |
return false; | |
} | |
} | |
} | |
/* Copy the rest of the file: */ | |
for (int ch = fgetc(infile); ch != EOF; ch = fgetc(infile)) | |
fputc(ch, outfile); | |
return true; | |
} | |
int encodeBit(FILE *infile, FILE *outfile, char bit) | |
{ | |
for (int ch = fgetc(infile); ch != EOF; ch = fgetc(infile)) { | |
if (ch == '\n') { | |
if (bit) | |
fputc(' ', outfile); | |
fputc('\n', outfile); | |
return ch; | |
} | |
fputc(ch, outfile); | |
} | |
return EOF; | |
} | |
char *duplicateString(const char *s) | |
{ | |
assert(s); | |
assert(strlen(s) > 0); | |
char *copy = malloc(strlen(s) + 1); | |
assert(copy); | |
return strcpy(copy, s); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment