Untitled

 avatar
unknown
plain_text
6 months ago
7.3 kB
3
Indexable
To use a terminator for the embedded message, we'll modify the code to embed a special sequence (e.g., a null character `\0`) at the end of the message. This will allow the extraction process to detect the end of the message dynamically without requiring the message length. 

Here's how you can implement this:

### Embedding with a Terminator

1. **Embedding**: 
   - Embed the message bit by bit into the DCT coefficients.
   - Append a null character (`\0`) at the end of the message to serve as a terminator.

2. **Extracting**:
   - Extract bits until you encounter the terminator (`\0`), signaling the end of the message.

### Modified Code

#### Embed Message with a Null Terminator

```c
void embed_message_with_terminator(png_bytep *image, int width, int height, const char *message) {
    int msg_index = 0;
    int msg_length = strlen(message) * 8 + 8; // Including space for the null terminator
    double block[BLOCK_SIZE][BLOCK_SIZE];

    for (int y = 0; y < height; y += BLOCK_SIZE) {
        for (int x = 0; x < width; x += BLOCK_SIZE) {
            if (msg_index >= msg_length) break;

            // Load an 8x8 block
            for (int i = 0; i < BLOCK_SIZE; i++) {
                for (int j = 0; j < BLOCK_SIZE; j++) {
                    if (y + i < height && x + j < width) {
                        block[i][j] = (double)image[y + i][4 * (x + j)]; // Using red channel
                    } else {
                        block[i][j] = 0.0;
                    }
                }
            }

            // Perform DCT on the block
            dct(block);

            // Embed a bit of the message into the DCT coefficients
            int bit;
            if (msg_index / 8 < strlen(message)) {
                bit = (message[msg_index / 8] >> (7 - (msg_index % 8))) & 1;
            } else {
                // Embed the null terminator
                bit = 0;
            }

            if (block[1][1] > 0) {
                block[1][1] = bit ? fabs(block[1][1]) : -fabs(block[1][1]);
            } else {
                block[1][1] = bit ? -fabs(block[1][1]) : fabs(block[1][1]);
            }
            msg_index++;

            // Perform inverse DCT on the block
            inverse_dct(block);

            // Store the modified block back into the image
            for (int i = 0; i < BLOCK_SIZE; i++) {
                for (int j = 0; j < BLOCK_SIZE; j++) {
                    if (y + i < height && x + j < width) {
                        image[y + i][4 * (x + j)] = (png_byte)fmin(fmax(block[i][j], 0.0), 255.0);
                    }
                }
            }
        }
    }
}

int main(int argc, char *argv[]) {
    if (argc != 4) {
        fprintf(stderr, "Usage: %s <input_png> <output_png> <message>\n", argv[0]);
        return 1;
    }

    const char *input_filename = argv[1];
    const char *output_filename = argv[2];
    const char *message = argv[3];

    png_bytep *image = NULL;
    int width, height;

    // Read the input PNG image
    read_png_file(input_filename, &image, &width, &height);

    // Embed the message with a null terminator in the image
    embed_message_with_terminator(image, width, height, message);

    // Write the output PNG image
    write_png_file(output_filename, image, width, height);

    // Free memory
    for (int y = 0; y < height; y++) {
        free(image[y]);
    }
    free(image);

    printf("Message embedded and saved to %s\n", output_filename);
    return 0;
}
```

#### Extract Message with a Null Terminator

```c
void extract_message_with_terminator(png_bytep *image, int width, int height, char *output_message, int max_length) {
    int msg_index = 0;
    int bit_value;
    double block[BLOCK_SIZE][BLOCK_SIZE];
    
    for (int y = 0; y < height && msg_index < max_length * 8; y += BLOCK_SIZE) {
        for (int x = 0; x < width && msg_index < max_length * 8; x += BLOCK_SIZE) {
            // Load an 8x8 block
            for (int i = 0; i < BLOCK_SIZE; i++) {
                for (int j = 0; j < BLOCK_SIZE; j++) {
                    if (y + i < height && x + j < width) {
                        block[i][j] = (double)image[y + i][4 * (x + j)];
                    } else {
                        block[i][j] = 0.0;
                    }
                }
            }

            // Perform DCT on the block
            dct(block);

            // Extract the bit from DCT coefficients
            bit_value = block[1][1] > 0 ? 1 : 0;
            output_message[msg_index / 8] |= (bit_value << (7 - (msg_index % 8)));
            msg_index++;

            // Check for the null terminator
            if (msg_index % 8 == 0 && output_message[msg_index / 8 - 1] == '\0') {
                return;
            }
        }
    }

    // Null-terminate the extracted message (in case it's not found)
    output_message[msg_index / 8] = '\0';
}

void read_embedded_message(const char *input_filename, int max_message_length) {
    png_bytep *image = NULL;
    int width, height;
    char *extracted_message = malloc((max_message_length + 1) * sizeof(char));
    memset(extracted_message, 0, (max_message_length + 1) * sizeof(char));

    // Read the input PNG image
    read_png_file(input_filename, &image, &width, &height);

    // Extract the message with a null terminator from the image
    extract_message_with_terminator(image, width, height, extracted_message, max_message_length);

    // Free memory
    for (int y = 0; y < height; y++) {
        free(image[y]);
    }
    free(image);

    printf("Extracted Message: %s\n", extracted_message);
    free(extracted_message);
}

int main_extract(int argc, char *argv[]) {
    if (argc != 3) {
        fprintf(stderr, "Usage: %s <input_png> <max_message_length>\n", argv[0]);
        return 1;
    }

    const char *input_filename = argv[1];
    int max_message_length = atoi(argv[2]);

    // Extract the message from the image
    read_embedded_message(input_filename, max_message_length);

    return 0;
}
```

### Explanation

1. **Embedding**:
   - In `embed_message_with_terminator`, the message is embedded as usual with an added null character (`\0`) to indicate the end of the message.
   - The DCT coefficients in `block[1][1]` are modified to include these bits.

2. **Extracting**:
   - In `extract_message_with_terminator`, the function reads the image, extracts the bits from the DCT coefficients, and stops when it detects the null terminator (`\0`).
   - This makes the extraction dynamic and removes the need for providing the message length.

3. **Usage**:
   - To embed a message with terminator: `./stego_embed input.png output.png "Your Message"`
   - To extract the message: `./stego_extract output.png <max_message_length>` (max message length here is just to limit memory allocation, but the extraction stops at the terminator).

### Notes

- This approach allows the message to be extracted without knowing its exact length, improving usability.
- Ensure the `max_message_length` in extraction is large enough to cover the embedded message. If it's too small, the extraction process will prematurely terminate.
- This code uses a single channel (red) for simplicity, but you can expand it to use other channels for more embedding capacity.
Editor is loading...
Leave a Comment