Программа стеганографии дает странные результаты

Я занимаюсь разработкой программы стеганографии для класса компьютерного программирования. Похоже, дает случайные символы ASCII. Выход должен быть двоичным. Метод кодирования сообщений был предоставлен нам моим учителем. Нам просто нужно запрограммировать часть декодирования.

import java.awt.*;
class HideMessage {
    public void encodeMessage(Picture stegoObject, int[] binaryArray) {
        Pixel pixelTarget = new Pixel(stegoObject, 0, 0);
        Pixel[] pixelArray = stegoObject.getPixels();
        Color pixelColor = null;
        int redValue = 0;

        for (int x = 0; x < binaryArray.length; x++) {
            redValue = binaryArray[x];
            pixelTarget = pixelArray[x];
            pixelTarget.setRed(redValue);
        }
        pixelTarget = pixelArray[binaryArray.length];
        pixelTarget.setRed(255);
        System.out.println("FinishedPic");
        stegoObject.write("SecretMessage.bmp");
        stegoObject.explore();

    }
    public void decodeMessage(Picture decodepic) {

        int redValue = 0;
        Pixel targetPixel = null;
        Color pixelColor = null;
        int sum = 0;

        for (int x = 0; redValue < 2; x++) {
                //inside nested loop to traverse the image from left to right
                for (int count = 1; count < 9; count++) {

                    targetPixel =
                        decodepic.getPixel(count + (8 * x), 0);
                    //gets the x,y coordinate of the target pixel
                    pixelColor = targetPixel.getColor();
                    //gets the color of the target pixel

                    redValue = pixelColor.getRed();

                    if (redValue == 1) {
                        if (count == 1) {
                            sum = sum + 128;
                        }
                        if (count == 2) {
                            sum = sum + 64;
                        }
                        if (count == 3) {
                            sum = sum + 32;
                        }
                        if (count == 4) {
                            sum = sum + 16;
                        }
                        if (count == 5) {
                            sum = sum + 8;
                        }
                        if (count == 6) {
                            sum = sum + 4;
                        }
                        if (count == 7) {
                            sum = sum + 2;
                        }
                        if (count == 8) {
                            sum = sum + 1;
                        }
                    }

                    System.out.println(sum);

                }
                System.out.println((char)sum);
                sum = 0;
            }   //end of the inner for loop
    }
}

public class HideMessageTester {
    public static void main(String[] args) {
        int[] bitArray =
            { 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1,
           0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0,
           1, 1, 1, 1, 0, 0, 1 };
        //int[] bitArray =
        { 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1,
                0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1,
                1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0,
                0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1,
                0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0,
                0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1,
                0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1,
                0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
                0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1,
                0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1,
                1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0,
                0, 1, 0, 0, 0, 0, 1};

        Picture stegoObject = new Picture("Earth.bmp");

        HideMessage stego = new HideMessage();

        stego.encodeMessage(stegoObject, bitArray);
        Picture decodeObject = new Picture("SecretMessage.bmp");
        System.out.println("Now Decoding");
        stego.decodeMessage(decodeObject);
    }
}

1 ответ

Решение

Во-первых, несколько общих советов: я думаю, что ваша программа слишком сложна, потому что функции объединяют свои обязанности:

Picture stegoObject = new Picture("Earth.bmp");
HideMessage stego = new HideMessage();
stego.encodeMessage(stegoObject, bitArray);
Picture decodeObject = new Picture("SecretMessage.bmp");
System.out.println("Now Decoding");
stego.decodeMessage(decodeObject);

Я был очень удивлен, увидев SecretMessage.bmp; было совсем не очевидно, что вы пытаетесь декодировать объект, который вы только что создали. Конечно, после прочтения encodeMessage() Методом было достаточно легко определить, откуда он взялся, но я думаю, что этот поток был бы проще:

/* encode */
Picture pic_to_steg = new Picture("foo.bmp");
HideMessage stego = new HideMessage();
Picture secret = stego.encodeMessage(pic_to_steg, bitArray);
secret.write("SecretMessage.bmp");

/* decode */
Picture pic_with_message = new Picture("SecretMessage.bmp");
int[] hidden = stego.decodeMessage(pic_with_message);

/* output `hidden` and compare against `bitArray` */

Другими словами: оставьте файл ввода-вывода целиком до основного потока программы. Возможно, ваши подпрограммы будут вызываться с сетевого сервера в будущем, и изображения никогда не будут сохранены на диск. Эта модификация будет намного проще, если подпрограммы работают на Pictureи возвращение исправлено Pictureс и int[],

Можете ли вы проверить свой encodeMessage() метод в изоляции? Возможно, посмотрите на различия в том, что он делает между входным файлом и выходным файлом. Этот раздел выглядит хлопотно:

public void encodeMessage(Picture stegoObject, int[] binaryArray) {
    Pixel pixelTarget = new Pixel(stegoObject, 0, 0);
    Pixel[] pixelArray = stegoObject.getPixels();
    Color pixelColor = null;
    int redValue = 0;

    for (int x = 0; x < binaryArray.length; x++) {
        redValue = binaryArray[x];
        pixelTarget = pixelArray[x];
        pixelTarget.setRed(redValue);
    }
    pixelTarget = pixelArray[binaryArray.length];
    pixelTarget.setRed(255);

Это pixelArray действительно ссылка на изображение, которое можно обновить с помощью простого назначения? Я действительно ожидал бы, что дизайн будет больше похож на этот псевдокод:

pixel p = image.getPixel(x, y);
p.setred(binaryArray[i]);
image.setPixel(x, y, p);

У декодирования есть несколько странных циклов:

    for (int x = 0; redValue < 2; x++) {
            //inside nested loop to traverse the image from left to right
            for (int count = 1; count < 9; count++) {

Этот цикл может работать точно так, как вы его спроектировали, но при первом прочтении он выглядит очень неправильно: вы начинаете с x=0Вы увеличиваете x каждый раз через цикл, но вы используете redValue < 2 как ваше правило завершения цикла.

Я бы предпочел, чтобы цикл был написан так:

int x = 0;
while (redValue < 2) {
    /* stuff */
    x++;
}

(Это не идентично; x все еще действует вне цикла, что может быть опасно. Тем не менее, я думаю, что это гораздо яснее.)

Есть случаи, когда условие о прекращении for Цикл не связан с пунктами настройки или приращения - по моему опыту, они очень редки.

В этом случае, однако, это похоже на ошибку; состояние redValue < 2 инвариант цикла, но внутренний цикл предполагает, что это произойдет только с пикселями, кратными 8, что является предположением, которое не применяется в encodeMessage() метод.

Попытка вычислить целочисленное значение из вашего redValueТо, что вы читаете их, без необходимости усложняет вашу процедуру декодирования. Я предлагаю удалить внутренний цикл и вернуть массив точно так же, как массив, переданный в encodeMessage() рутина. Это будет (а) легче (б) легче отлаживать (в) легче тестировать (г) в тысячу раз легче обрабатывать записи битовых массивов, которые не делятся поровну на 8.

Затем напишите второй метод, который преобразует вывод битового массива в сумму, или символы ASCII, или символы EBCDIC, или параметры ключа RSA, или все, что кодируется. Не пытайтесь сделать слишком много сразу. Написание отдельного метода для декодирования массива битов будет (а) легче (б) легче отлаживать (в) легче тестировать (г) в тысячу раз проще для обработки произвольных модификаций вывода.

Я надеюсь, что эти подсказки помогут.

Другие вопросы по тегам