隐写术程序给出了奇怪的结果

时间:2011-06-30 22:19:37

标签: java awt steganography

我正在为计算机编程课开发一个隐写程序。它似乎给出了随机的ascii符号。输出应该是BINARY。编码消息方法由我的老师给我们。我们只需要对解码部分进行编程。

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 个答案:

答案 0 :(得分:2)

首先,一些一般建议:我认为你的程序过于复杂,因为功能正在混合他们的职责:

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` */

换句话说:将文件IO完全保留到程序的主流程中。也许您的例程将来会从网络服务器调用,并且图片永远不会保存到磁盘。如果例程在Picture上运行并返回修改后的Pictureint[],那么修改将会容易得多。

您可以单独测试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()例程的数组一样。这将是(a)更容易(b)更容易调试(c)更容易测试(d)更容易处理写入不能被8整除的位数组。

然后编写一个第二方法,将位数组输出转换为和,或ASCII字符,或EBCDIC字符,或RSA关键参数,或任何正在编码的内容。不要试图一次做太多。编写一个单独的方法来解码位数组将是(a)更容易(b)更容易调试(c)更容易测试(d)更容易处理任意输出修改数千次。

我希望这些提示有所帮助。