Beispiel #1
0
        private int[] shuffled; // shuffled sequence

        // The constructor of class Permutation creates a shuffled
        // sequence of the integers 0 ... (size-1).
        internal Permutation(int size, F5Random random)
        {
            int i, randomIndex;

            this.shuffled = new int[size];

            // To create the shuffled sequence, we initialise an array
            // with the integers 0 ... (size-1).
            for (i = 0; i < size; i++)
            {
                // initialise with "size" integers
                this.shuffled[i] = i;
            }
            int maxRandom = size; // set number of entries to shuffle

            for (i = 0; i < size; i++)
            {
                // shuffle entries
                randomIndex = random.GetNextValue(maxRandom--);
                Swap(ref this.shuffled[maxRandom], ref this.shuffled[randomIndex]);
            }
        }
        /// <summary>
        /// This method controls the compression of the image. Starting at the
        /// upper left of the image, it compresses 8x8 blocks of data until the
        /// entire image has been compressed.
        /// </summary>
        /// <param name="out"></param>
        private void WriteCompressedData()
        {
            // This initial setting of MinBlockWidth and MinBlockHeight is done to
            // ensure they start with values larger than will actually be the case.
            int MinBlockWidth = this.imageWidth % 8 != 0 ? (int)(Math.Floor(this.imageWidth / 8.0) + 1) * 8 : this.imageWidth;
            int MinBlockHeight = this.imageHeight % 8 != 0 ? (int)(Math.Floor(this.imageHeight / 8.0) + 1) * 8 : this.imageHeight;
            int comp, shuffledIndex;
            for (comp = 0; comp < JpegInfo.NumberOfComponents; comp++)
            {
                MinBlockWidth = Math.Min(MinBlockWidth, this.JpegObj.BlockWidth[comp]);
                MinBlockHeight = Math.Min(MinBlockHeight, this.JpegObj.BlockHeight[comp]);
            }

            int[] lastDCvalue = new int[JpegInfo.NumberOfComponents];
            int[] emptyArray = new int[64];
            int[] coeff = GetCoeff(MinBlockWidth, MinBlockHeight);
            int coeffCount = coeff.Length;
            int i, j, r, c;
            int _changed = 0;
            int _embedded = 0;
            int _examined = 0;
            int _expected = 0;
            int _one = 0;
            int _large = 0;
            int _thrown = 0;
            int _zero = 0;

            logger.Info("got " + coeffCount + " DCT AC/DC coefficients");
            for (i = 0; i < coeffCount; i++)
            {
                if (i % 64 == 0)
                    continue;
                else if (coeff[i] == 1 || coeff[i] == -1)
                    _one++;
                else if (coeff[i] == 0)
                    _zero++;
            }
            _large = coeffCount - _zero - _one - coeffCount / 64;
            _expected = _large + (int)(0.49 * _one);
            //

            logger.Info("one=" + _one);
            logger.Info("large=" + _large);
            //
            logger.Info("expected capacity: " + _expected + " bits");
            logger.Info("expected capacity with");

            for (i = 1; i < 8; i++)
            {
                int usable, changed, n;
                n = (1 << i) - 1;
                usable = _expected * i / n - _expected * i / n % n;
                changed = coeffCount - _zero - coeffCount / 64;
                changed = changed * i / n - changed * i / n % n;
                changed = n * changed / (n + 1) / i;
                //
                changed = _large - _large % (n + 1);
                changed = (changed + _one + _one / 2 - _one / (n + 1)) / (n + 1);
                usable /= 8;
                if (usable == 0)
                    break;
                if (i == 1)
                    logger.Info("default");
                else
                    logger.Info("(1, " + n + ", " + i + ")");
                logger.Info(" code: " + usable + " bytes (efficiency: " + usable * 8 / changed + "." +
                    usable * 80 / changed % 10 + " bits per change)");
            }

            // westfeld
            if (this.embeddedData != null)
            {
                // Now we embed the secret data in the permutated sequence.
                logger.Info("Permutation starts");
                F5Random random = new F5Random(Encoding.ASCII.GetBytes(this.password));
                Permutation permutation = new Permutation(coeffCount, random);
                int nextBitToEmbed = 0;
                int byteToEmbed = Convert.ToInt32(this.embeddedData.Length);
                int availableBitsToEmbed = 0;
                // We start with the length information. Well,
                // the length information it is more than one
                // byte, so this first "byte" is 32 bits long.

                /*try {
                    byteToEmbed = this.embeddedData.available();
                } catch (final Exception e) {
                    e.printStackTrace();
                }*/

                logger.Info("Embedding of " + (byteToEmbed * 8 + 32) + " bits (" + byteToEmbed + "+4 bytes) ");
                // We use the most significant byte for the 1 of n
                // code, and reserve one extra bit for future use.
                if (byteToEmbed > 0x007fffff)
                {
                    byteToEmbed = 0x007fffff;
                }
                // We calculate n now
                for (i = 1; i < 8; i++)
                {
                    int usable;
                    this.n = (1 << i) - 1;
                    usable = _expected * i / this.n - _expected * i / this.n % this.n;
                    usable /= 8;
                    if (usable == 0)
                    {
                        break;
                    }
                    if (usable < byteToEmbed + 4)
                    {
                        break;
                    }
                }
                int k = i - 1;
                this.n = (1 << k) - 1;
                switch (this.n)
                {
                    case 0:
                        logger.Info("using default code, file will not fit");
                        this.n++;
                        break;
                    case 1:
                        logger.Info("using default code");
                        break;
                    default:
                        logger.Info("using (1, " + this.n + ", " + k + ") code");
                        break;
                }
                byteToEmbed |= k << 24; // store k in the status word
                // Since shuffling cannot hide the distribution, the
                // distribution of all bits to embed is unified by
                // adding a pseudo random bit-string. We continue the random
                // we used for Permutation, initially seeked with password.
                byteToEmbed ^= random.GetNextByte();
                byteToEmbed ^= random.GetNextByte() << 8;
                byteToEmbed ^= random.GetNextByte() << 16;
                byteToEmbed ^= random.GetNextByte() << 24;
                nextBitToEmbed = byteToEmbed & 1;
                byteToEmbed >>= 1;
                availableBitsToEmbed = 31;
                _embedded++;

                for (i = 0; i < permutation.Length; i++)
                {
                    int shuffled_index = permutation.GetShuffled(i);

                    if (shuffled_index % 64 == 0 || coeff[shuffled_index] == 0)
                        continue;

                    var cc = coeff[shuffled_index];
                    _examined += 1;

                    if (cc > 0 && (cc & 1) != nextBitToEmbed)
                    {
                        coeff[shuffled_index]--;
                        _changed++;
                    }
                    else if (cc < 0 && (cc & 1) == nextBitToEmbed)
                    {
                        coeff[shuffled_index]++;
                        _changed++;
                    }

                    if (coeff[shuffled_index] != 0)
                    {
                        if (availableBitsToEmbed == 0)
                        {
                            if (n > 1 || embeddedData.Available == 1)
                                break;

                            byteToEmbed = embeddedData.Read();
                            byteToEmbed ^= random.GetNextByte();
                            availableBitsToEmbed = 8;
                        }
                        nextBitToEmbed = byteToEmbed & 1;
                        byteToEmbed >>= 1;
                        availableBitsToEmbed--;
                        _embedded++;
                    }
                    else
                        _thrown++;
                }

                if (n > 1)
                {
                    bool isLastByte = false;
                    FilteredCollection filtered_index = permutation.Filter(coeff, i + 1);
                    while (!isLastByte)
                    {
                        int kBitsToEmbed = 0;
                        for (i = 0; i < k; i++)
                        {
                            if (availableBitsToEmbed == 0)
                            {
                                if (embeddedData.Available == 0)
                                {
                                    isLastByte = true;
                                    break;
                                }
                                byteToEmbed = embeddedData.Read();
                                byteToEmbed ^= random.GetNextByte();
                                availableBitsToEmbed = 8;
                            }
                            nextBitToEmbed = byteToEmbed & 1;
                            byteToEmbed >>= 1;
                            availableBitsToEmbed--;
                            kBitsToEmbed |= nextBitToEmbed << i;
                            _embedded++;
                        }

                        List<int> codeWord = filtered_index.Offer(this.n);
                        int extractedBit;
                        while (true)
                        {
                            int vhash = 0;
                            int count = codeWord.Count;
                            for (i = 0; i < count; i++)
                            {
                                int index = codeWord[i];
                                extractedBit = coeff[index] > 0 ? coeff[index] & 1 : (1 - (coeff[index] & 1));
                                if (extractedBit == 1)
                                {
                                    vhash ^= i + 1;
                                }
                            }
                            i = vhash ^ kBitsToEmbed;
                            if (i == 0)
                                break;
                            i--;

                            if (coeff[codeWord[i]] < 0)
                                coeff[codeWord[i]]++;
                            else
                                coeff[codeWord[i]]--;
                            _changed++;

                            if (coeff[codeWord[i]] == 0)
                            {
                                _thrown++;
                                codeWord.RemoveAt(i);
                                codeWord.Add(filtered_index.Offer());
                            }
                        }
                    }
                }
            }

            logger.Info("Starting Huffman Encoding.");
            shuffledIndex = 0;
            for (r = 0; r < MinBlockHeight; r++)
            {
                for (c = 0; c < MinBlockWidth; c++)
                {
                    for (comp = 0; comp < JpegInfo.NumberOfComponents; comp++)
                    {
                        for (i = 0; i < JpegObj.VsampFactor[comp]; i++)
                        {
                            for (j = 0; j < JpegObj.HsampFactor[comp]; j++)
                            {
                                Array.Copy(coeff, shuffledIndex, emptyArray, 0, 64);
                                this.huffman.HuffmanBlockEncoder(this.output, emptyArray, lastDCvalue[comp],
                                    this.JpegObj.DCtableNumber[comp], this.JpegObj.ACtableNumber[comp]);
                                lastDCvalue[comp] = emptyArray[0];
                                shuffledIndex += 64;
                            }
                        }
                    }
                }
            }
            this.huffman.FlushBuffer(this.output);
        }
        private int[] shuffled; // shuffled sequence

        #endregion Fields

        #region Constructors

        // The constructor of class Permutation creates a shuffled
        // sequence of the integers 0 ... (size-1).
        internal Permutation(int size, F5Random random)
        {
            int i, randomIndex;
            this.shuffled = new int[size];

            // To create the shuffled sequence, we initialise an array
            // with the integers 0 ... (size-1).
            for (i = 0; i < size; i++)
            {
                // initialise with "size" integers
                this.shuffled[i] = i;
            }
            int maxRandom = size; // set number of entries to shuffle
            for (i = 0; i < size; i++)
            {
                // shuffle entries
                randomIndex = random.GetNextValue(maxRandom--);
                Swap(ref this.shuffled[maxRandom], ref this.shuffled[randomIndex]);
            }
        }
 public JpegExtract(Stream output, byte[] password)
 {
     this.output = output;
     this.random = new F5Random(password);
 }