First commit
This commit is contained in:
commit
c851620cd4
BIN
main
Executable file
BIN
main
Executable file
Binary file not shown.
326
main.c
Normal file
326
main.c
Normal file
@ -0,0 +1,326 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdint.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#define BUFSIZE 8192
|
||||
#define SPLIT 128
|
||||
|
||||
// gcc -Wno-all -ggdb -O0 main.c -lz -o main && ./main hide mountains.png text.txt
|
||||
|
||||
// Structure of each chunks
|
||||
// http://www.libpng.org/pub/png/spec/1.2/PNG-Structure.html#Chunk-layout
|
||||
|
||||
// http://www.libpng.org/pub/png/spec/1.2/PNG-Structure.html#PNG-file-signature
|
||||
struct signature{
|
||||
unsigned char bytes[8];
|
||||
} __attribute__((packed));
|
||||
// __attribute__((packed)) -> for removing padding
|
||||
// GCC add padding in the struct, 3 bytes
|
||||
//https://stackoverflow.com/questions/1841863/size-of-struct-in-c
|
||||
|
||||
struct chunk{
|
||||
unsigned char length[4];
|
||||
char type[4];
|
||||
} __attribute__((packed));
|
||||
|
||||
// http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html#C.IHDR
|
||||
struct iHDR{
|
||||
unsigned char width[4];
|
||||
unsigned char height[4];
|
||||
char depth;
|
||||
char type;
|
||||
char compression;
|
||||
char filter;
|
||||
char interlace;
|
||||
// Chunk crc
|
||||
unsigned char crc[4];
|
||||
} __attribute__((packed));
|
||||
|
||||
/* PROTOTYPES */
|
||||
static int hide_message(int, char **);
|
||||
static int unhide_message(int, char **);
|
||||
static int getHeader(int, char *);
|
||||
static size_t insertChunk(int, const char *, size_t, int);
|
||||
static void convert_from_uint(unsigned char *, const unsigned int);
|
||||
static void convert_from_bytes(const unsigned char *, unsigned int *);
|
||||
|
||||
|
||||
int main(int argc, char *argv[], char **envp){
|
||||
int fd_r;
|
||||
|
||||
// The two statements below check if the arguments passed are correct
|
||||
if (argc < 4){
|
||||
printf("Usage: %s <hide|unhide> <picture> <text file>\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
if (strcmp(argv[1], "hide") != 0 && strcmp(argv[1], "unhide") != 0){
|
||||
printf("ok\n");
|
||||
printf("usage: %s <hide|unhide> <picture> <text file>\n", argv[0]);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
// https://man7.org/linux/man-pages/man2/open.2.html
|
||||
// The next two statements open the picture src and destination
|
||||
if ((fd_r = open(argv[2], O_RDONLY)) == -1){
|
||||
printf("Failed to open the png file %s\n", argv[1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "hide") == 0){
|
||||
hide_message(fd_r, argv);
|
||||
}
|
||||
if (strcmp(argv[1], "unhide") == 0){
|
||||
unhide_message(fd_r, argv);
|
||||
}
|
||||
close(fd_r);
|
||||
}
|
||||
/*
|
||||
* In this function, we will hide the text provide in argument of the program to
|
||||
* the destination image
|
||||
*/
|
||||
static int hide_message(int fd_r, char **argv){
|
||||
int fd_w;
|
||||
int fd_r_text;
|
||||
size_t length;
|
||||
size_t length_text_to_hide;
|
||||
char *buf;
|
||||
char text[BUFSIZE];
|
||||
char tmp[8];
|
||||
struct chunk *s_chunk = {0};
|
||||
char buffer[sizeof(struct signature) + sizeof(struct chunk) + sizeof(struct iHDR)];
|
||||
int end = 0;
|
||||
|
||||
if ((fd_w = open("dest.png", O_WRONLY | O_CREAT, 00644)) == -1){
|
||||
printf("Failed to create the dest file\n");
|
||||
close(fd_r);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// The two next statements, we open the text to hide and buffer it
|
||||
if ((fd_r_text = open(argv[3], O_RDONLY)) == -1){
|
||||
printf("Failed to open the png file %s\n", argv[3]);
|
||||
close(fd_r);
|
||||
close(fd_w);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((length_text_to_hide = read(fd_r_text, text, BUFSIZE)) == -1){
|
||||
printf("Failed to read the file %s\n", argv[3]);
|
||||
close(fd_r);
|
||||
close(fd_w);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the header and the IHDR and copy to the dest file
|
||||
length = getHeader(fd_r, buffer);
|
||||
|
||||
if (length == 0){
|
||||
printf("Failed to get the png header\n");
|
||||
close(fd_w);
|
||||
return -1;
|
||||
}
|
||||
write(fd_w, buffer, length);
|
||||
|
||||
// TODO
|
||||
// For the text, we split it into different chunk. We split the size defined by the global variable SPLIT
|
||||
// Each chunk are inserted between differents chunks
|
||||
// We insert the text
|
||||
/*if (length_text_to_hide > SPLIT){
|
||||
|
||||
}*/
|
||||
length = insertChunk(fd_w, text, length_text_to_hide, 0);
|
||||
|
||||
|
||||
// We will parse each chunk until the IEND chunk
|
||||
do{
|
||||
unsigned int s = 0;
|
||||
// read the 8 bytes (for the chunk length and type)
|
||||
length = read(fd_r, tmp, 8);
|
||||
s_chunk = (struct chunk*)(tmp);
|
||||
|
||||
// Write the chunk block (length and type) without the CRC
|
||||
write(fd_w, tmp, length);
|
||||
|
||||
// Get the size of the data
|
||||
convert_from_bytes(s_chunk->length, &s);
|
||||
|
||||
// We add 4 bytes for the CRC
|
||||
s += 4;
|
||||
|
||||
// Identify the chunk
|
||||
if (s_chunk->type[0] == 'I' && s_chunk->type[1] == 'E' &&
|
||||
s_chunk->type[2] == 'N' && s_chunk->type[3] == 'D'){
|
||||
end = 1;
|
||||
}
|
||||
|
||||
// The next statements allocate the buf with the chunk data size
|
||||
// and read the chunk data with the CRC
|
||||
buf = malloc(s);
|
||||
|
||||
// read the file
|
||||
length = read(fd_r, buf, s);
|
||||
write(fd_w, buf, length);
|
||||
|
||||
memset(tmp, 0, 8);
|
||||
free(buf);
|
||||
}while(end != 1);
|
||||
|
||||
close(fd_w);
|
||||
close(fd_r_text);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int unhide_message(int fd_r, char **argv){
|
||||
int fd_w;
|
||||
int length;
|
||||
char buffer[sizeof(struct signature) + sizeof(struct chunk) + sizeof(struct iHDR)];
|
||||
struct chunk *s_chunk;
|
||||
char tmp[8];
|
||||
char *buf;
|
||||
int end = 0;
|
||||
|
||||
// The statement below check if we can create the file for the output
|
||||
if ((fd_w = open(argv[3], O_WRONLY | O_CREAT, 00644)) == -1){
|
||||
printf("Failed to write the output text file %s\n", argv[3]);
|
||||
close(fd_r);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the header and the IHDR
|
||||
length = getHeader(fd_r, buffer);
|
||||
if (length == 0){
|
||||
printf("Failed to get the png header\n");
|
||||
close(fd_w);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// We will parse each chunk until the IEND chunk
|
||||
do{
|
||||
unsigned int s = 0;
|
||||
unsigned char crc[4];
|
||||
// read the 8 bytes (for the chunk length and type)
|
||||
length = read(fd_r, tmp, 8);
|
||||
s_chunk = (struct chunk*)(tmp);
|
||||
|
||||
// Identify the chunk
|
||||
if (s_chunk->type[0] == 'I' && s_chunk->type[1] == 'E' &&
|
||||
s_chunk->type[2] == 'N' && s_chunk->type[3] == 'D'){
|
||||
end = 1;
|
||||
}
|
||||
|
||||
// Get the size of the data
|
||||
convert_from_bytes(s_chunk->length, &s);
|
||||
|
||||
// The next statements allocate the buf with the chunk data size
|
||||
// and read the chunk data with the CRC
|
||||
buf = malloc(s);
|
||||
|
||||
// read the file
|
||||
length = read(fd_r, buf, s);
|
||||
if (s_chunk->type[0] == 's' && s_chunk->type[1] == 'T' &&
|
||||
s_chunk->type[2] == 'E' && s_chunk->type[3] == 'G'){
|
||||
write(fd_w, buf, length);
|
||||
}
|
||||
|
||||
// Read the crc
|
||||
read(fd_r, crc, 4);
|
||||
|
||||
memset(tmp, 0, 8);
|
||||
free(buf);
|
||||
}while(end != 1);
|
||||
|
||||
close(fd_w);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* In this function, we put our chunk to the file
|
||||
* this chunk contain our text message to hide
|
||||
*/
|
||||
static size_t insertChunk(int fd_w, const char *buf, size_t text_length, int start){
|
||||
int length;
|
||||
unsigned char crc[4];
|
||||
unsigned int crc_z;
|
||||
struct chunk s_chunk;
|
||||
memset(crc, 0, 4);
|
||||
|
||||
// We create our chunk layout and write to the file
|
||||
convert_from_uint(s_chunk.length, text_length);
|
||||
|
||||
s_chunk.type[0] = 's';
|
||||
s_chunk.type[1] = 'T';
|
||||
s_chunk.type[2] = 'E';
|
||||
s_chunk.type[3] = 'G';
|
||||
|
||||
write(fd_w, s_chunk.length, 4);
|
||||
write(fd_w, s_chunk.type, 4);
|
||||
|
||||
length = write(fd_w, buf, text_length);
|
||||
|
||||
// Generate the CRC and write it to the file
|
||||
crc_z = crc32(0L, Z_NULL, 0);
|
||||
crc_z = crc32(crc_z, s_chunk.type, 4);
|
||||
crc_z = crc32(crc_z, buf, text_length);
|
||||
|
||||
convert_from_uint(crc, crc_z);
|
||||
length = write(fd_w, crc, 4);
|
||||
|
||||
return length;
|
||||
}
|
||||
/*
|
||||
* This function convert the unsigned int 32 bits to bytes and store to the buf variable
|
||||
*/
|
||||
static void convert_from_uint(unsigned char *buf, const unsigned int uint){
|
||||
buf[0] = (unsigned char)((uint >> 24) & 0xFFU);
|
||||
buf[1] = (unsigned char)((uint >> 16) & 0xFFU);
|
||||
buf[2] = (unsigned char)((uint >> 8) & 0xFFU);
|
||||
buf[3] = (unsigned char)(uint & 0xFFU);
|
||||
}
|
||||
/*
|
||||
* This function convert the bytes buf to unsigned int 32 bits
|
||||
*/
|
||||
static void convert_from_bytes(const unsigned char *buf, unsigned int *uint){
|
||||
*uint = buf[3] + (buf[2] << 8) + (buf[1] << 16) + (buf[0] << 24);
|
||||
}
|
||||
/*
|
||||
* This function read thefile for getting the signature, the 8 first bytes
|
||||
* and get the IHDR which contains some information regarding the picture
|
||||
*/
|
||||
static int getHeader(int fd_r, char *buf){
|
||||
size_t size_hdr = sizeof(struct signature) + sizeof(struct chunk) + sizeof(struct iHDR);
|
||||
int length;
|
||||
int i;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
struct signature *s_sign = {0};
|
||||
struct iHDR *s_ihdr = {0};
|
||||
|
||||
// Get the PNG signature and the header
|
||||
length = read(fd_r, buf, size_hdr);
|
||||
|
||||
if (length == 0)
|
||||
return 0;
|
||||
|
||||
// Display signature data
|
||||
s_sign = (struct signature *)buf;
|
||||
printf("Signature\n");
|
||||
for (i = 0; i < sizeof(struct signature); i++)
|
||||
printf("%x ", s_sign->bytes[i]);
|
||||
printf("\n\n");
|
||||
|
||||
// Display header data
|
||||
s_ihdr = (struct iHDR*)(buf + sizeof(struct signature) + sizeof(struct chunk));
|
||||
|
||||
printf("Size of the image:\n");
|
||||
convert_from_bytes(s_ihdr->width, &width);
|
||||
convert_from_bytes(s_ihdr->height, &height);
|
||||
printf("Width: %upx\nHeight: %upx\n", width, height);
|
||||
|
||||
return length;
|
||||
}
|
BIN
mountains.png
Normal file
BIN
mountains.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 MiB |
2
text.txt
Normal file
2
text.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Hello world!
|
||||
I am a message hidden in the picture :)
|
Loading…
Reference in New Issue
Block a user