Click here to Skip to main content
15,881,757 members
Articles / Programming Languages / C#

Steganography 13 - Hiding Binary Data in HTML Documents

Rate me:
Please Sign up or sign in to vote.
4.94/5 (45 votes)
13 Mar 2008CPOL5 min read 180.5K   1.7K   52  
Some ideas on how to hide binary data in text documents
#region Using directives

using System;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;

#endregion

namespace SteganoHtml {



    partial class MainForm : Form {

        DataSet keySet = new DataSet();
        DataTable keyTable;

        public MainForm() {
            InitializeComponent();
        }

        private void Form2_Load(object sender, EventArgs e) {
            keyTable = keySet.Tables.Add("keyCombinations");
            dgvKey.DataSource = keyTable;

            keyTable.Columns.Add("firstAttribute", typeof(String));
            keyTable.Columns.Add("secondAttribute", typeof(String));

            keyTable.Columns["firstAttribute"].Caption = "First Attribute";
            keyTable.Columns["secondAttribute"].Caption = "Second Attribute";

            keyTable.Columns["firstAttribute"].Unique = true;
            keyTable.Columns["secondAttribute"].Unique = true;

            keyTable.Columns["firstAttribute"].AllowDBNull = false;
            keyTable.Columns["secondAttribute"].AllowDBNull = false;

            keyTable.Rows.Add("width", "height");
            keyTable.Rows.Add("src", "alt");
            keyTable.Rows.Add("style", "class");
            keyTable.Rows.Add("cellspacing", "cellpadding");
        }

        private void IsKeyValid() {
            foreach (DataRow row in keyTable.Rows) {
                if (row[0].ToString().Length == 0) {
                    row[0] = DBNull.Value;
                }
                if (row[1].ToString().Length == 0) {
                    row[1] = DBNull.Value;
                }
            }
        }

        private void btnHide_Click(object sender, EventArgs e)
        {
            HtmlUtility utility = new HtmlUtility();

            int capacity = utility.GetCapacity(txtSrcFileName.Text, keyTable);
            int requiredCapacity = (txtMessageHide.Text.Length + 1) * 8;
            if (requiredCapacity > capacity) {

                String warning = "The document contains not enough attributes.";
                warning += "\r\nCapacity: " + capacity.ToString();
                warning += "\r\nRequired: " + requiredCapacity.ToString();
                MessageBox.Show(warning);

            } else {

                MemoryStream message = new MemoryStream();
                BinaryWriter binaryWriter = new BinaryWriter(message);
                binaryWriter.Write((byte)txtMessageHide.Text.Length);
                binaryWriter.Write( Encoding.Default.GetBytes(txtMessageHide.Text.ToCharArray()) );
                
                this.Cursor = Cursors.WaitCursor;
                utility.Hide(txtSrcFileName.Text, txtDstFileName.Text, message, keyTable);
                this.Cursor = Cursors.Default;

                binaryWriter.Close();

                MessageBox.Show("Finished");
            }
        }

        private void btnExtract_Click(object sender, EventArgs e)
        {
            HtmlUtility utility = new HtmlUtility();
            MemoryStream message = new MemoryStream();

            this.Cursor = Cursors.WaitCursor;
            utility.Extract(txtSrcFileName.Text, message, keyTable);
            this.Cursor = Cursors.Default;

            message.Position = 0;
            StreamReader reader = new StreamReader(message, Encoding.Default);
            String messageText = reader.ReadToEnd();
            txtMessageExtract.Text = messageText;

            reader.Close();
        }

        private String GetSourceFileName(String filter) {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Filter = filter;
            if (dlg.ShowDialog(this) == DialogResult.OK) {
                return dlg.FileName;
            } else {
                return null;
            }
        }

        private String GetDestinationFileName(String filter) {
            SaveFileDialog dlg = new SaveFileDialog();
            dlg.Filter = filter;
            if (dlg.ShowDialog(this) == DialogResult.OK) {
                return dlg.FileName;
            } else {
                return null;
            }
        }

        private void btnSrcFileName_Click(object sender, EventArgs e)
        {
            String fileName = GetSourceFileName("HTML Documents (*.html, *.html)|*.html;*.htm");
            if (fileName != null) {
                txtSrcFileName.Text = fileName;
            }
        }

        private void btnDstFileName_Click(object sender, EventArgs e) {
            String fileName = GetDestinationFileName("HTML Documents (*.html, *.html)|*.html;*.htm");
            if (fileName != null) {
                txtDstFileName.Text = fileName;
            }
        }

        private void btnLoadKey_Click(object sender, EventArgs e) {
            String fileName = GetSourceFileName("XML Key Files (*.xml)|*.xml");
            if (fileName != null) {
                keyTable.Clear();
                keyTable.ReadXml(fileName);
            }
        }

        private void btnSaveKey_Click(object sender, EventArgs e) {
            String fileName = GetDestinationFileName("XML Key Files (*.xml)|*.xml");
            if (fileName != null) {
                keyTable.WriteXml(fileName);
            }
        }

        private void dgvKey_Leave(object sender, EventArgs e)
        {
            IsKeyValid();
        }

        private void btnAnalyse_Click(object sender, EventArgs e)
        {
            HtmlUtility utility = new HtmlUtility();
            //free bits = overall bits - 16 bits for message length
            int countBits = utility.GetCapacity(txtSrcFileName.Text, keyTable) - 8;
            if (countBits < 8) {
                MessageBox.Show(
                    "The file cannot hide any data. Add more attribute pairs to your key to raise the capacity."
                    );
            } else {
                int countChars = (int)Math.Floor(((double)countBits) / 8);
                MessageBox.Show(
                    String.Format("The file can hide {0} bits ({1} characters). Add more attribute pairs to your key to raise the capacity.", countBits, countChars)
                    );
            }
        }

        private void txtMessageHide_TextChanged(object sender, EventArgs e)
        {
            lblCountCharacters.Text = txtMessageHide.Text.Length.ToString();
        }

    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Germany Germany
Corinna lives in Hanover/Germany and works as a C# developer.

Comments and Discussions