【问题标题】:Steganography: how to change the LSB of a pixel array隐写术:如何更改像素阵列的 LSB
【发布时间】:2018-10-02 20:03:27
【问题描述】:

我正在使用 lodePNG 库对 png 图像进行编码,并使用导入的 txt 文件更改像素的 LSB。我已经编译了程序,但我不确定 PNG 文件是否实际上是根据我的按位运算进行编码的。

lodePNG 库从 PNG 图像解码/编码,并将像素存储在矢量“图像”中,每个像素 4 个字节,有序 RGBARGBA...,

void decodeOneStep(const char* filename)
{

      unsigned width, height;

      //decode
      unsigned error = lodepng::decode(image, width, height, filename);

      //if there's an error, display it
      if (error) std::cout << "decoder error " << error << ": " << 
          lodepng_error_text(error) << std::endl;
}

程序采用文本文件和 PNG 文件的命令行参数。我还没有包括参数的错误检查。

int const MAX_SIZE = 100; 
std::vector<unsigned char> image;

int main(int argc, char *argv[])
{
const char* filename;
char* textArray = new char[MAX_SIZE];

std::ifstream textfile;
textfile.open(argv[1]);

int numCount = 0;
while (!textfile.eof() && numCount < MAX_SIZE)
{
    textfile.get(textArray[numCount]); //reading single character from file to array
    numCount++;
}

textfile.close();

    filename = argv[2];
    decodeOneStep(filename);

    unsigned width = 512, height = 512;
    image.resize(width * height * 4);

    int pixCount = 0; 

    for (int i = 0; i < numCount - 1; i++) {

        std::cout << textArray[i]; 

        for (int j = 0; j < 8; j++) {

            std::cout << ((textArray[i]) & 1); //used to see actual bit value.
            image[pixCount++] |= ((textArray[i]) & 1);
            (textArray[i]) >>= 1; 
        }                       
        std::cout << std::endl; 
    } 

encodeOneStep(filename, image, width, height);

在 for 循环中,我将遍历向量中的每个像素,并将 LSB 替换为 char 中的位。由于一个 char 是 8 个字节,所以 for 循环循环了 8 次。这个程序应该适用于大多数不超过大小的 PNG 图像和文本,但我不确定按位运算实际上是否在做任何事情。另外,我如何能够移动这些位,以便我们将 char 位从 MSB 存储到 LSB?我觉得我理解像素值(位)如何存储在数组中的方式有​​问题。

编辑:测试我在新的位操作上运行:

    for (int j = 7; j >= 0; j--) {

        //These tests were written to see if the 4-bits of the pixels were actually being replaced.
        //The LSB of the pixel bits are replaced with the MSB of the text character. 

        std::cout <<"Initial pixel 4-bits: " << std::bitset <4>(image[pixCount]) << "  "; 
        std::cout << "MSB of char: " << ((textArray[i] >> j) & 0x01) << " ";
        std::cout << "Pixel LSB replaced: " << ((image[pixCount] & mask) | ((textArray[i] >> j) & 0x01)) << " ";

        image[pixCount] = (image[pixCount] & mask) | ((textArray[i] >> j) & 0x01);
        pixCount++;

        std::cout << std::endl;

    }

测试结果:

For char 'a' 
Initial pixel 4-bits : 0000 MSB: 0 Pixel LSB replaced: 0
Initial pixel 4-bits : 0001 MSB: 1 Pixel LSB replaced: 1
Initial pixel 4-bits : 0001 MSB: 1 Pixel LSB replaced: 1
Initial pixel 4-bits : 0000 MSB: 0 Pixel LSB replaced: 0
Initial pixel 4-bits : 0000 MSB: 0 Pixel LSB replaced: 0
Initial pixel 4-bits : 0000 MSB: 0 Pixel LSB replaced: 0
Initial pixel 4-bits : 0000 MSB: 0 Pixel LSB replaced: 0
Initial pixel 4-bits : 0001 MSB: 1 Pixel LSB replaced: 1

【问题讨论】:

  • 如果文本包含 1,image[pixCount++] |= ((textArray[i]) &amp; 1); 似乎会添加一点。但如果文本包含 0,您还必须从图像中删除一点。

标签: c++ encryption cryptography bit-manipulation steganography


【解决方案1】:

在嵌入秘密位之前,您首先需要清除像素的 lsb。

unsigned char mask = 0xfe;  // in binary 11111110

// and in your loop
image[pixCount] = (image[pixCount] & mask) | (textArray[i] & 1);
pixCount++;

如果您想从最高有效位到最低有效位嵌入秘密的每个字符的位,您需要倒计时j 循环。

for (int j = 7; j >= 0; j--) {
    image[pixCount] = (image[pixCount] & mask) | ((textArray[i] >> j) & 0x01);
    pixCount++;
}

编辑:为了解释上面的代码,image[pixCount] &amp; mask 是您的像素和所选掩码值(二进制 1111110)之间的 AND 运算符,因此结果是清除 lsb。

(textArray[i] &gt;&gt; j) &amp; 0x01 将您的 char 向左移动 j 并且只保留 lsb。如果你算出数学,这就是你得到的

// assume our character has the bits `abcdefgh`

j = 7
(character >> j) & 0x01 = 0000000a & 0x01 = a

j = 6
(character >> j) & 0x01 = 000000ab & 0x01 = b

j = 5
(character >> j) & 0x01 = 00000abc & 0x01 = c

// and so on

j = 0
(character >> j) & 0x01 = abcdefgh & 0x01 = h

【讨论】:

  • 感谢您的帮助!代码位中到底发生了什么(图像[pixCount] 和掩码)| ((textArray[i] >> j) & 0x01); ? OR 运算符如何使代码从 MSB 添加到 LSB?
  • @Joe 我已经添加了解释。我还注意到我有一个错字。循环中的条件应该是j &gt;= 0,而不是j &lt;= 0,现在已经更正了。
  • 非常感谢您的帮助!它真的帮了很多忙。我对您解释的位操作有最后一个问题。当我对这些位如何变化进行测试时(将测试添加到 EDIT),我得到的结果表明像素位的初始 LSB 已经更改为文本的 MSB。当我还没有更改任何内容时,为什么这会显示附加值?
  • @Joe 你正在做一些我无法复制的奇怪事情。我创建了一个带有 8 个值的向量的简单程序,只有 j 循环,所有内容都按预期打印。无论如何,这与发布的原始问题不同,值得提出自己的问题。对问题所做的任何编辑都应该是为了澄清或添加相关信息,而不是为了将目标移至新问题。
猜你喜欢
  • 2021-10-07
  • 2016-05-25
  • 2018-08-01
  • 2016-08-18
  • 2018-09-13
  • 2013-08-18
  • 2018-07-29
  • 2012-11-19
相关资源
最近更新 更多