Created
August 15, 2024 16:10
-
-
Save h4k1m0u/f217fe174a629163f93a8c95371df37e to your computer and use it in GitHub Desktop.
Use steganography to read/write a textual password from/to sequential pixels' least-significant bits
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 <string.h> | |
#include <stdbool.h> | |
#include <gd.h> | |
#include "utils.h" | |
/** | |
* Print password written beforehand on image with steganography_write.c | |
* - GD documentation: https://libgd.github.io/manuals/2.1.1/files/preamble-txt.html | |
* | |
* How to build & run: | |
* $ gcc -lgd utils.c steganography_read.c -o steganography_read | |
* $ ./steganography image.png | |
*/ | |
int main(int argc, char** argv) { | |
if (argc != 2) { | |
printf("USAGE: %s IMAGE\n", argv[0]); | |
return 1; | |
} | |
const char* filename = argv[1]; | |
// input png image | |
FILE* file = fopen(filename, "rb"); | |
if (file == NULL) { | |
perror("Error"); | |
return 1; | |
} | |
gdImagePtr image = gdImageCreateFromPng(file); | |
const int WIDTH = image->sx; | |
const int HEIGHT = image->sy; | |
printf("w: %d, h: %d\n", WIDTH, HEIGHT); | |
int x = 0; | |
int y = 0; | |
size_t i_c = 0; | |
char password[100]; | |
// read password characters from image | |
while (true) { | |
// each password character spans 8 pixel | |
char c = 0; | |
for (size_t i_b = 0; i_b < CHAR_BIT; i_b++) { | |
int value = gdImageGetTrueColorPixel(image, x, y); | |
bool bit = value & 1; | |
c += bit << i_b; | |
move_to_next_pixel(&x, &y, WIDTH); | |
} // END BITS | |
password[i_c++] = c; | |
// null terminator character reached | |
if (c == 0) | |
break; | |
} | |
printf("Password: %s\n", password); | |
// free assets | |
fclose(file); | |
gdImageDestroy(image); | |
return 0; | |
} |
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 <string.h> | |
#include <stdbool.h> | |
#include <gd.h> | |
#include "utils.h" | |
/** | |
* Write given password on image, starting from pixel (0, 0) & proceeding row by row | |
* Each password's bit is written to the least-significant bit of the rgb value of each pixel | |
* The password is terminated with a null character ('\0') | |
* - GD documentation: https://libgd.github.io/manuals/2.1.1/files/preamble-txt.html | |
* | |
* How to build & run: | |
* $ gcc -lgd utils.c steganography_write.c -o steganography_write | |
* $ ./steganography image_in.png "my password" image_out.png | |
*/ | |
int main(int argc, char** argv) { | |
if (argc != 4) { | |
printf("USAGE: %s IMAGE_IN PASSWORD IMAGE_OUT\n", argv[0]); | |
return 1; | |
} | |
const char* filename_in = argv[1]; | |
const char* password = argv[2]; | |
const char* filename_out = argv[3]; | |
// input png image | |
FILE* file_in = fopen(filename_in, "rb"); | |
if (file_in == NULL) { | |
perror("Error"); | |
return 1; | |
} | |
gdImagePtr image = gdImageCreateFromPng(file_in); | |
const int WIDTH = image->sx; | |
const int HEIGHT = image->sy; | |
printf("w: %d, h: %d\n", WIDTH, HEIGHT); | |
int x = 0; | |
int y = 0; | |
// write password characters to image | |
printf("\nWriting password characters...\n"); | |
for (size_t i_c = 0; i_c < strlen(password); i_c++) { | |
char c = password[i_c]; | |
printf("\n- c: %c %d - ", c, c); | |
for (size_t i_b = 0; i_b < CHAR_BIT; i_b++) { | |
bool bit = (c >> i_b) & 1; | |
printf(bit ? "1" : "0"); | |
int value = gdImageGetTrueColorPixel(image, x, y); | |
// set or clear least-significant bit | |
if (bit) | |
value |= 1; | |
else | |
value &= ~1; | |
gdImageSetPixel(image, x, y, value); | |
move_to_next_pixel(&x, &y, WIDTH); | |
} // END BITS | |
} // END CHARACTERS | |
// write null terminator | |
printf("\nWriting null terminator...\n"); | |
printf("Unsetting from pixel (%d, %d)...\n", x, y); | |
for (size_t i_b = 0; i_b < CHAR_BIT; i_b++) { | |
int value = gdImageGetTrueColorPixel(image, x, y); | |
value &= ~1; | |
gdImageSetPixel(image, x, y, value); | |
move_to_next_pixel(&x, &y, WIDTH); | |
} | |
// output png image | |
FILE* file_out = fopen(filename_out, "wb"); | |
gdImagePng(image, file_out); | |
// free assets | |
fclose(file_out); | |
fclose(file_in); | |
gdImageDestroy(image); | |
return 0; | |
} |
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 "utils.h" | |
void move_to_next_pixel(int* x, int* y, int width) { | |
*x += 1; | |
if (*x == width) { | |
*x = 0; | |
*y += 1; | |
} | |
} |
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 UTILS_HPP | |
#define UTILS_HPP | |
void move_to_next_pixel(int* x, int* y, int width); | |
#endif // UTILS_HPP |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment