有损压缩中的隐写术 (JAVA)
Steganography in lossy compression (JAVA)
我有这个用于在 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
jpeg 使用有损压缩方法来实现更小的文件大小。不幸的是,这种方法直接影响(某些)像素的值,从而破坏了您嵌入信息的方式。您需要将文件保存为无损格式,例如bmp或png。
Jpeg 隐写术的代码有点复杂,但概念很简单。您将需要编写一个 jpeg 编码器,或者使用一个已经存在的编码器。您链接到的代码确实是一个编码器,只需进行一些小的修改,您就可以将其用于您的项目。
如果想看懂代码,可以阅读jpeg encoding上的维基百科文章。我将简要总结它的一些关键步骤。
- 将图像拆分为 8x8 块。
- 对每个使用离散余弦变换 (DCT) 以获得浮点 DCT 系数并将它们量化为整数。
- 使用霍夫曼编码和 运行 长度编码将量化系数存储到文件中。
第二步的量化是有损的,后面的都是无损的。所以基本上,从第二步获得量化系数,用你的隐写算法修改它们,然后继续第三步。
关于链接代码的实际修改。 Compress
方法是将 rgb 图像存储到文件中需要调用的方法。它负责写入 header 数据和压缩系数。您只需要在 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();
}
}
}
我有这个用于在 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
jpeg 使用有损压缩方法来实现更小的文件大小。不幸的是,这种方法直接影响(某些)像素的值,从而破坏了您嵌入信息的方式。您需要将文件保存为无损格式,例如bmp或png。
Jpeg 隐写术的代码有点复杂,但概念很简单。您将需要编写一个 jpeg 编码器,或者使用一个已经存在的编码器。您链接到的代码确实是一个编码器,只需进行一些小的修改,您就可以将其用于您的项目。
如果想看懂代码,可以阅读jpeg encoding上的维基百科文章。我将简要总结它的一些关键步骤。
- 将图像拆分为 8x8 块。
- 对每个使用离散余弦变换 (DCT) 以获得浮点 DCT 系数并将它们量化为整数。
- 使用霍夫曼编码和 运行 长度编码将量化系数存储到文件中。
第二步的量化是有损的,后面的都是无损的。所以基本上,从第二步获得量化系数,用你的隐写算法修改它们,然后继续第三步。
关于链接代码的实际修改。 Compress
方法是将 rgb 图像存储到文件中需要调用的方法。它负责写入 header 数据和压缩系数。您只需要在 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();
}
}
}