Функция стеганографии отлично работает с текстом, но искажает двоичный вывод - PullRequest
1 голос
/ 03 августа 2020

Я пытаюсь встроить файл в изображение, используя последние 2 LSB каждого цвета в каждом пикселе (последние 3 в случае синего), и всякий раз, когда я кодирую / декодирую, текст работает нормально, но любой двоичный такие данные, как файлы ELF, случайные данные и т. д. c, смешиваются. Вот моя функция стеганографии и дестеганографии:

bool steganographize(int height, int width, unsigned long long filesize, unsigned char *file, RGBTRIPLE image[height][width], bmpstatus about)
{
    int f = 0; //for char access
    int i = 0;
    int j = 0;

    for (i = 0 ; i < height; i++)
    {
        if (f >= filesize)
        {
            goto finis;
        }

        for (j = 0 ; j < width; j++)
        {
            if (f >= filesize)
            {
                goto finis;
            }

            image[i][j].rgbtRed = ((image[i][j].rgbtRed & ~0x3) | ((file[f] & 0x60) >> 5));
            image[i][j].rgbtGreen = ((image[i][j].rgbtGreen & ~0x3) | ((file[f] & 0x18) >> 3));
            image[i][j].rgbtBlue = ((image[i][j].rgbtBlue & ~0x7) | ((file[f] & 0x7)));
            f++;
        }
    }
finis:
    if (f == (filesize))
    {
        printf("%d\n", i);
        printf("%d\n", j);
        
        print_status("Embedded file into BMP");

        print_status("Inserting EOF");

        image[i][j].rgbtRed = 0;
        image[i][j].rgbtGreen = 92;
        image[i][j].rgbtBlue = 183;

        image[i][j + 1].rgbtRed = 12;
        image[i][j + 1].rgbtGreen = 57;
        image[i][j + 1].rgbtBlue = 237;

        image[i + 1][j].rgbtRed = 91;
        image[i + 1][j].rgbtGreen = 34;
        image[i + 1][j].rgbtBlue = 45;

        return true;
    }

    return false;
}
bool desteganographize(int height, int width, RGBTRIPLE image[height][width], bmpstatus about, FILE* output)
{
    unsigned char* buffer = calloc(height * width * 3, sizeof(unsigned char));
    int i = 0;
    int j = 0;
    int f = 0;

    for (i = 0; i < height; i++)
    {
        for (j = 0; j < width; j++)
        {
            if (image[i][j].rgbtRed == 0 && image[i][j].rgbtGreen == 92 && image[i][j].rgbtBlue == 183) {
                if (image[i][j + 1].rgbtRed == 12 && image[i][j + 1].rgbtGreen == 57 && image[i][j + 1].rgbtBlue == 237 
                    && image[i + 1][j].rgbtRed == 91 && image[i + 1][j].rgbtGreen == 34 && image[i + 1][j].rgbtBlue == 45) {
                        goto finis;
                    } 
            }

            unsigned char c = 
                    ((image[i][j].rgbtRed & 0x3) << 5) | 
                    ((image[i][j].rgbtGreen & 0x3) << 3 ) |
                    (image[i][j].rgbtBlue & 0x7);
            buffer[f] = c;
            f++;
        }
    }

    finis: 
        fwrite(buffer, sizeof(unsigned char), f, output);
        printf("%d\n", i);
        printf("%d\n", j);
        fclose(output);
        return true;
    
    return false;
}

Вот соответствующие части моей основной функции:

int main(int argc, char** argv) {
        if (strstr(argv[1], encode) != NULL) {
          FILE *bmp = fopen(bitmap, "rb");
          bmpstatus *result = is_valid_bmp(bmp);

          if (result == NULL)
          {
            print_error("Bad BMP. Maybe you specified the wrong file?");
          }

          //Get BMP into memory
          char buffer[BUFFER_LEN];
          sprintf(buffer, "Found BMP of Height %d and width %d", result->height, result->width);
          print_status(buffer);
          cleararr(buffer);

          int width = result->width;
          int height = result->height;
          RGBTRIPLE(*image)
          [width] = calloc(height, width * sizeof(RGBTRIPLE));

          if (!scanimage(height, width, bmp, image, *result))
          {
              print_error("Error scanning BMP into memory. Probably not enough RAM.");
          }
          print_status("Scanned BMP into memory");

          //Scan file into memory
          unsigned long long filesize = file_size(fopen(filename, "rb"));

          sprintf(buffer, "Found file with %llu kilobytes", filesize / 1024);
          print_status(buffer);
          cleararr(buffer);

          if (filesize > ((unsigned long long)width * height * 3) / 8)
          {
              print_error("Bitmap not big enough to hold file");
          }

          unsigned char *file = calloc(filesize, sizeof(unsigned char));
          printf("%llu\n", filesize);

          if (!scan_file(file, filesize, fopen(filename, "rb")))
          {
              print_error("Error scanning file into memory");
          }
          print_status("Scanned file into memory");


          if (!steganographize(height, width, filesize, file, image, *result))
          {
              print_error("Error embedding file into BMP");
          }

          //Output manipulated BMP
          sprintf(buffer, "Outputting finished BMP to %s", output);
          print_status(buffer);
          outputimage(height, width, fopen(output, "wb"), image, *result);
          cleararr(buffer);


          free(result);
          free(image);
          free(file);
          print_success("Finished!");
          return 0;
  }

   if (strstr(argv[1], decode)) {
       bmpstatus *result = is_valid_bmp(input);

        if (result == NULL)
        {
            print_error("Bad BMP");
        }

        int height = result->height;
        int width = result->width;
        RGBTRIPLE(*image)
        [width] = calloc(height, width * sizeof(RGBTRIPLE));

        char buffer[BUFFER_LEN];

        sprintf(buffer, "Found a BMP with height %d and width %d", height, width);
        print_status(buffer);
        cleararr(buffer);

        if (!scanimage(height, width, input, image, *result))
        {
            print_error("Cannot scan BMP into memory. Not enough RAM, maybe?");
        }

        print_status("Scanned BMP into memory");

        char tmpname[16] = "/tmp/tmp.XXXXXX";

        mkstemp(tmpname);
        print_status("Made temporary file");

        FILE* finish = fopen(tmpname, "wb");

        if (!desteganographize(height, width, image, *result, finish)) {
            print_error("Could not extract file.");
        }

            free(result);
        free(image);
        return 0;
    }
}

Это не самый элегантный способ, но похоже, что он выполняет свою работу (по крайней мере, для текста). bmpstatus - это структура, имеющая высоту и ширину bmp, размер файла - размер входных данных, а RGBTRIPLE - это структура с 3 элементами: красным, зеленым и синим. Я убедился, что эти два работают. scanimage получает BMP и помещает его в матрицу RGBTRIPLE, а scan_file принимает указатель файла и сканирует данные в массив беззнаковых символов. Все это работает, поэтому я предполагаю, что это связано с самими функциями стеганографии.

1 Ответ

2 голосов
/ 04 августа 2020

Оказалось, что я читал только 7 бит из каждого символа вместо 8. Как только я заменил 0x60 на 0xe0 и 0x3 на 0x7 в красном компоненте, все заработало.

...