有损压缩中的隐写术 (JAVA)

Posted

技术标签:

【中文标题】有损压缩中的隐写术 (JAVA)【英文标题】:Steganography in lossy compression (JAVA) 【发布时间】:2015-06-23 00:53:30 【问题描述】:

我有这个用于在 java 中的 jpeg 图像中编码数据。我正在将文本转换为其二进制形式并将其插入到从 (0,0) 到 (width,height) 的每个像素中的 RGB 的 LSB(取决于用户选择的内容。1,2,3,4) .

outer:
    for(int i = 0; i < height; i++)
        for(int j = 0; j < width; j++)
            Color c = new Color(image.getRGB(j, i));                  

            int red = binaryToInteger(insertMessage(integerToBinary((int)(c.getRed())),numLSB));
            int green = binaryToInteger(insertMessage(integerToBinary((int)(c.getGreen())),numLSB));
            int blue = binaryToInteger(insertMessage(integerToBinary((int)(c.getBlue())),numLSB));

            Color newColor = new Color(red,green,blue);
            image.setRGB(j,i,newColor.getRGB());

        
    
    gui.appendStatus("Binarized message is: " + binarizedMessage);
    File output = new File(gui.getOutput()+".jpg");

    ImageIO.write(image, "png", output);

目前,我将它写成 png 并且效果很好,但我希望在 jpeg 中制作它。我成功地在 png 中获取了这些数据。但正如预期的那样,在 jpeg 中失败了。

如果选择了正确的 LSB,我能够解码图像中的隐藏位并查看消息。

我目前正在阅读有关 JPEG 隐写术的信息,但不完全了解我应该如何开始它。我看过算法,也没有帮助我。

我看到一个没有找到任何主类的代码。

我必须在我的应用程序中调用它吗?修改它?我将如何解码?

这是我见过的link to a code。

【问题讨论】:

【参考方案1】:

jpeg 使用有损压缩方法来实现更小的文件大小。不幸的是,这种方法直接影响(某些)像素的值,从而破坏了您嵌入信息的方式。您需要将文件保存为无损格式以避免此问题,例如 bmp 或 png。

Jpeg 隐写术的代码有些复杂,但概念很简单。您将需要编写一个 jpeg 编码器,或者使用已经存在的一个。您链接到的代码确实是一个编码器,只需稍加修改,您就可以将其用于您的项目。

如果你想了解代码,可以阅读***文章jpeg encoding。我将简要总结它的一些关键步骤。

将图像分割成 8x8 块。 对每个使用离散余弦变换 (DCT) 来获得浮点 DCT 系数并将它们量化为整数。 使用霍夫曼编码和游程编码将量化系数存储到文件中。

第二步的量化是有损位,但之后的一切都是无损的。所以基本上,从第二步获得量化系数,用你的隐写算法修改它们,然后继续第三步。

关于链接代码的实际修改。 Compress 方法是将 rgb 图像存储到文件中需要调用的方法。它负责写入标题数据和压缩系数。您只需要在WriteCompressedData 方法中添加一些代码。它现在所做的是遍历每个 8x8 图像块,应用 dct 并量化存储在dctArray3 中的系数。然后将此数据压缩写入文件。这就是你必须干预的地方,在调用Huf.HuffmanBlockEncoder之前修改dctArray3

例如,假设您有一个名为 message 的秘密字节数组,并且您想在特定系数的 lsb 中嵌入每个 8x8 块的一位。

public void WriteCompressedData(BufferedOutputStream outStream, byte[] message) 
    byte currentByte;
    int nBytes = message.length;
    int iByte = 0;
    int iBit = 7;
    if (nBytes > 0) 
        currentByte = message[0];
     else 
        currentByte = (byte) 0;
    
    // Original method code up until the following line
    dctArray3 = dct.quantizeBlock(dctArray2, JpegObj.QtableNumber[comp]);
    // ******************** our stuff *******************
    if (iByte < nBytes) 
        int bit = (currentByte >> iBit) & 1;
        iBit--;
        if (iBit == -1) 
            iBit = 7;
            iByte++;
            if (iByte < nBytes) 
                currentByte = message[iByte];
            
        
        dctArray3[23] = (dctArray3[23] & 0xfffffffe) | bit;
    
    // **************************************************
    Huf.HuffmanBlockEncoder(outStream, dctArray3, lastDCvalue[comp], JpegObj.DCtableNumber[comp], JpegObj.ACtableNumber[comp]);
    ...

解码与此相反,您可以读取 DCT 系数并使用适当的算法从中提取您的秘密。为此,您将需要一个 jpeg 解码器,所以我只是从F5 Steganography 项目中借用了相关文件。具体来说,你需要ortega文件夹中的文件,然后就可以这样使用了。

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import ortega.HuffmanDecode;

public class Extract 
    private static byte[] deZigZag = 
            0, 1, 5, 6, 14, 15, 27, 28, 2, 4, 7, 13, 16, 26, 29, 42, 3, 8, 12, 17, 25, 30, 41, 43, 9, 11, 18, 24, 31,
            40, 44, 53, 10, 19, 23, 32, 39, 45, 52, 54, 20, 22, 33, 38, 46, 51, 55, 60, 21, 34, 37, 47, 50, 56, 59, 61,
            35, 36, 48, 49, 57, 58, 62, 63 ;

    private static int[] extract(InputStream fis, int flength) throws IOException 
        byte[] carrier = new byte[flength];
        fis.read(carrier);
        HuffmanDecode hd = new HuffmanDecode(carrier);
        int[] coeff = hd.decode();
        return coeff;
    

    public static void main(String[] args) 
        // run with argument the stego jpeg filename
        try 
            File f = new File(args[0]);
            FileInputStream fis = new FileInputStream(f);
            int[] coeff = extract(fis, (int) f.length());

            int idx = deZigZag[23];
            // The coeff array has all of the DCT coefficients in one big
            // array, so that the first 64 elements are the coefficients 
            // from the first block, the next 64 from the second and so on.
            //
            // idx is the position of the embedding DCT coefficient.
            // You can start with that and extract its lsb, then increment
            // by 64 to extract the next bit from the next "block" and so on.
         catch (Exception e) 
            e.printStackTrace();
        
    

【讨论】:

本周末晚些时候我会检查你的这个答案。谢谢你的回答:) 我更正了编码序列逻辑中的一个错误(应该是if (iBit == -1)而不是0)并添加了一个解码器示例。 我可以用我的方法对图像进行编码,调用原来的JpegEncoder,让它写图像。然后我反转它的过程,最后,我应用我的解码过程。可行吗? 用你的方法对图像进行编码是什么意思?您的意思是在像素中嵌入信息然后保存为 jpeg 吗? 就像之前指出的那样,您不能将数据嵌入像素中,然后将其编码为 jpeg。 Jpeg 文件通过存储 DCT 系数来实现压缩。如上所述,这是一个无损过程。你必须使用文件格式给你的东西。为了无损存储像素,您需要使用不同的格式。

以上是关于有损压缩中的隐写术 (JAVA)的主要内容,如果未能解决你的问题,请参考以下文章

PDF文件中的隐写术[关闭]

Python 中的隐写术 - Stepic

在 PHP 中阻止图像主机的隐写术?

隐写术总结

隐写术总结

猥琐的隐写术