0

イメージステガノグラフィー(ロスレスイメージ用)に関するプロジェクトを取得しました。その背後にあるプロセスを学ぼうとしています。しかし、メッセージを抽出するために実行すると、間違ったパスワード空の画像(データがエンコードされていない)に対して例外が生成されます。ピクセルをランダムに選択し、ハッシュセットを使用します。しかし、途中のいくつかのステップが理解できません。それらのステップの間違いが例外を引き起こすかどうかは疑問です。さらに、場合によっては、 間違ったパスワードでもプロジェクトが隠しメッセージを抽出します。これらの問題を解決するにはどうすればよいですか?

この長いコードをお詫びしますが、解決策を願っています..助けてくれてありがとう.

コードは次のとおりです。

//encoding data in image

private void EncodeByte(Bitmap bm, Bitmap visible_bm, Random rand,
        byte value, HashSet<string> used_positions)
    {
        for (int i = 0; i < 8; i++)
        {
            // Pick a position for the ith bit.
            int row, col, pix;
            PickPosition(bm, rand, used_positions, out row, out col, out pix);

            // Get the color's pixel components.
            Color clr = bm.GetPixel(row, col);
            byte r = clr.R;
            byte g = clr.G;
            byte b = clr.B;

疑問: 以下に示す「次の 2 行」で、格納する次のビットをどのように取得するか?

// Get the next bit to store.
            int bit = 0;
            if ((value & 1) == 1) bit = 1;  //’value’ is the byte to be encoded

// Update the color.
            switch (pix)
            {
                case 0:
                    r = (byte)((r & 0xFE) | bit);
                    break;
                case 1:
                    g = (byte)((g & 0xFE) | bit);
                    break;
                case 2:
                    b = (byte)((b & 0xFE) | bit);
                    break;
            }
            clr = Color.FromArgb(clr.A, r, g, b);
            bm.SetPixel(row, col, clr);

  // Move to the next bit in the value.
            value >>= 1;
        }
    }

  //decoding  image
  private string DecodeMessageInImage(Bitmap bm, string password)
    {
        // Initialize a random number generator.
        Random rand = new Random(obj.NumericPassword(password));

        // Create a new HashSet.
        HashSet<string> used_positions = new HashSet<string>();

        // Make a byte array big enough to hold the message length.
        int len = 0;
        byte[] bytes = BitConverter.GetBytes(len);

   // Decode the message length.
        for (int i = 0; i < bytes.Length; i++)
        {
            bytes[i] = DecodeByte(bm, rand, used_positions);
        }
        len = BitConverter.ToInt32(bytes, 0);

疑問: 次のチェック (len>10000 の場合) は適切ですか?

 // Sanity check.

        if(len>10000)
        {
            throw new InvalidDataException(
            "Message length " + len.ToString() +
                " is too big to make sense. Invalid password.");
        }

        // Decode the message bytes.
        char[] chars = new char[len];
        for (int i = 0; i < chars.Length; i++)
        {
            chars[i] = (char)DecodeByte(bm, rand, used_positions);
        }
        return new string(chars);
    }

    // Decode a byte.
    private byte DecodeByte(Bitmap bm, Random rand, HashSet<string>   used_positions)
    {

        byte value = 0;
        byte value_mask = 1;
        for (int i = 0; i < 8; i++)
        {
            // Find the position for the ith bit.
            int row, col, pix;
           obj.PickPosition(bm, rand, used_positions, out row, out col, out pix);

            // Get the color component value.
            byte color_value = 0;
            switch (pix)
            {
                case 0:
                    color_value = bm.GetPixel(row, col).R;
                    break;
                case 1:
                    color_value = bm.GetPixel(row, col).G;
                    break;
                case 2:
                    color_value = bm.GetPixel(row, col).B;
                    break;
            }

疑問: 次の仕組みを教えてください:

// Set the next bit if appropriate.
            if ((color_value & 1) == 1)
            {
                // Set the bit.
                value = (byte)(value | value_mask);
            }

            // Move to the next bit.
            value_mask <<= 1;
        }

        return value;
      }

疑い: この無限ループは例外を発生させますか?これは正しい条件ですか?

  // Pick an unused (r, c, pixel) combination.
    public void PickPosition(Bitmap bm, Random rand,
        HashSet<string> used_positions,
        out int row, out int col, out int pix)
    {
        for (; ; )
        {
            // Pick random r, c, and pix.
            row = rand.Next(0, bm.Width);
            col = rand.Next(0, bm.Height);
            pix = rand.Next(0, 3);

            // See if this location is available.
            string key =
                row.ToString() + "/" +
                col.ToString() + "/" +
                pix.ToString();
            if (!used_positions.Contains(key))
            {
                used_positions.Add(key);
                return;
            }
        }
      }

  // Convert a string password into a numeric value.
    public int NumericPassword(string password)
    {
        // Initialize the shift values to different non-zero values.
        int shift1 = 3;
        int shift2 = 17;

        // Process the message.
        char[] chars = password.ToCharArray();
        int value = 0;
        for (int i = 1; i < password.Length; i++)
        {
            // Add the next letter.
            int ch_value = (int)chars[i];
            value ^= (ch_value << shift1);
            value ^= (ch_value << shift2);

            // Change the shifts.
            shift1 = (shift1 + 7) % 19;
            shift2 = (shift2 + 13) % 23;
        }
        return value;
    }
4

1 に答える 1

1

まず、間違ったパスワードが受け入れられる理由:

2 つの異なるパスワードに対して同じ値を返す可能性がNumericPasswordあります (「<a href="https://en.wikipedia.org/wiki/Collision_%28computer_science%29" rel="nofollow">ハッシュ衝突」)。NumericPasswordは基本的にハッシュ関数であるため、衝突攻撃に対して脆弱です。ハッシュにより多くのバイトを使用することで状況を改善できますが、それには別のアルゴリズムと、より大きなシードを処理できる乱数ジェネレーターが必要になります。

その場合、乱数ジェネレーターは、同じハッシュを生成する場合、異なるパスワードに対して同じ一連の数字を生成します。つまり、ステガノグラフィック コンテンツの「解読」につながります。

パスワードをキーとして使用する暗号化アルゴリズムでデータ自体を暗号化することで、この状況を回避できます。

アルゴリズムについて

値が画像にどのようにパック/アンパックされるかについての質問については、Bitwise Operatorsをご覧ください。

  • 例えば:

    if ((value & 1) == 1) bit = 1;  //’value’ is the byte to be encoded
    

    値の最下位ビットを取り、それを 1 と比較します。値が 1 の場合は、1 にbit設定されます。これは、バイト値が単一ビットに分解され、画像のカラー値の最下位ビットに書き込まれる方法です。あなたが示した場合を除いて。

    bitwise and( &) 演算子の例: バイナリ値 がある場合、 を使用して、00101010を得るbitwise andことができます。0001011100000010

  • ビットシフト演算子 ( <<) も使用されます。あなたのケースでは、整数のビットを1つ左にシフトします(つまり、重要度を上に上げます)(<<= 1)。そこのマスクは、現在読み取られているビットを値に入れる必要がある場所をマスクするために使用されます。

    基本的に、エンコーディングとデコーディングの両方の機能で、バイト内のすべてのビットを下位から上位に反復します。次に、ピクセルの最下位ビットにパックすることにより、画像との間でそれぞれ1ビットずつ書き込みまたは読み取りを行います。

  • 長さのチェックは賢明ですが、別の条件 (つまり、イメージのサイズ、つまりコンテナーの実際のサイズに依存する条件) を選択します。画像にエンコードされたデータが指定されたパスワードでデコードできるかどうかをチェックすることにより、間違ったパスワードを検出する必要があります (サニティ チェック)。

    間違ったパスワードの場合、抽出された長さが不合理に長くなる可能性があります。ただし、これは間違ったパスワードを検出するための安全なチェックではありません (パスワードが間違っていると、長さが短い数値になる可能性もあります)。

  • PickPosition の「無限」ループ。このループは実際に無限になる可能性があります。つまり、画像に位置が残っていない場合です。個人的には、新しいランダム値を取得する前に、最初に「悪い」(つまり、既に使用されている) ピクセルの近傍を通過するアルゴリズムを選択します。

    この方法では、次の有効な位置を見つけるのに時間がかかる場合があります。また、有効な位置がまったく残っていないことのチェックが欠けていますが、表示されていないコードの一部で発生する可能性があります。

画像に格納できるビット数は、与えられたアルゴリズムで簡単に計算できます。このアルゴリズムは、各カラー チャネルの最下位ビットに情報を格納するため、ピクセルあたり 3 ビットを取得します。したがって、画像の総ビット数は次のようになります。

capacityInBits = width * height * 3
于 2012-06-14T17:13:47.473 に答える