Skip to content

Instantly share code, notes, and snippets.

@eanmos
Last active June 7, 2019 21:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eanmos/00b33bae3bf6567dc6a1275cd69c14da to your computer and use it in GitHub Desktop.
Save eanmos/00b33bae3bf6567dc6a1275cd69c14da to your computer and use it in GitHub Desktop.
Steganography
#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
#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