Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Clipboard Codec

4.85/5 (6 votes)
15 Apr 2015CPOL7 min read 26.9K   836  
Tool to obfuscate strings and small images on the Clipboard. Peek at the Clipboard to see DataFormats of the current content. C# implementation of the ASCII85 codec.

Clipboard Codec showing Peek results

Clipboard Codec showing Encode results

Introduction

It's nice to have a way to obfuscate the Clipboard. You can copy, encode, and paste text snippets or images that you want to protect with some level of privacy. This tool lets you do that. Later, on the other side of an email or in the sanctuary of your secret lab, you can copy, decode, and paste the snippets back to their original form.

It's also nice to know what kind of thing is on the Clipboard. You will find there are many Clipboard object formats beside text and images. This tool lets you Peek at the compatible System.Windows.Forms.DataFormats of the current Clipboard content. The first screenshot of Clipboard Encode Decode above shows the compatible DataFormats for a small image from a CodeProject web page.

Background

There is actually a second reason to mess up the Clipboard's content. If we choose the right encoding methods, we not only make the data unusable by the casual interloper, we can also change binary code into a form that uses only ASCII characters and can therefore pass on channels that allow ASCII-only data, such as plain text email or HTML form data. Of course we need decoding methods for each encoding so we can eventually un-mess the content.

Base64 encoding was invented exactly for this. See RFC's 1421 (obsolete), 2045 (MIME, section 6.8), 3548, or 4648 at http://www.ietf.org/rfc.html for details.

But wait, there's more. Many spies can look at a string and say, "Aha, that's Base64-encoded stuff!" What to do?  Well, try another Base, say Base85, which isn't a power of two and therefore is not simply a matter of regrouping bits and using the results as offsets into the ASCII table. Base85, later a very similar codec called ASCII85, is a less well-known scheme that enlarges the encoded string by only 5 bytes for 4 rather than Base64's 4 bytes for 3. Why? Well, its a bigger base. The point to keep in mind is that encoding with one or both of these methods increases the size of the encoded string.

An even more ancient codec is Rot13 or RotN where "N" is some number between 1 and 25. In this scheme, any character is replaced with a character that is N moves further on in the alphabet. For N = 13, 'A' becomes 'N', 'B' becomes 'O', etc. Replacement tricks can be made to other non-alphabetic ASCII characters, but this tool's RotN only replaces the upper and lower case alphabetic characters. The nice thing about this older encoding is that it does not increase the size of the encoded string from the original.

This tool always uses at least Base64 encoding and decoding. ASCII85 and/or RotN can be added to that.  Putting them all together surely produces an insurmountable defense against snippet snoopers. (This is where we say as-is software, no warranties explicit or implied, yadda yadda.)

Regarding the methods used here: encoded strings on the Clipboard are actually maintained as Unicode (System.String's).  That being said, Windows itself is nice enough to translate Unicode to ASCII when, for example, you paste 5L6L44GILuODhuOCueODiA== to a Cmd prompt. But there is really nothing Windows can do when pasting the Base64-decode of this which is 例え.テスト so decoded content may need to be pasted to Unicode-aware containers or apps like MS Word or this HTML page. But this is also where such data is most likely copied from.

BTW, you can paste 例え.テスト to a notepad doc and it will be correctly displayed but when you save such a .txt file, you will be forced to choose OK to save the non-ANSI characters as '?' giving you ??.??? for 例え.テスト or to select a different encoding to save in Unicode.

One last thing. Repeatedly clicking Encode is a wonderful way to abuse this tool. Clicking Decode the same number of times should bring back the object you started with. It's just that at some point I'm sure you hit a limit. I haven't tried pushing Clipboard Encode Decode to that point.

Some Code Details

Clicking the Peek button does inspection of the Clipboard's content without modifying it. Here is the event handler for clicking Peek. Notice it does four things:

C#
private void buttonPeek_Click(object sender, RoutedEventArgs e)
{
    bool got = false;
    textBox1.Text = (flipper = !flipper) ? "" : " ";
	
    ShowCompatibleFormats();
	
    string s = ClipboardPeekImage(ref got);
    if (got)
    {
        textBox1.Text += s;
        return;
    }
    textBox1.Text += ClipboardPeekString(ref got);
}

First it initializes the text in textBox1 to either an empty string or single space. This is alternated so repeated Peek clicks will show an update. It is just for positive feedback that the handler is being executed.

Next ShowCompatibleFormats is called to load compatible data formats into comboBox1 (bottom control on Window) for display.

Third, a string s is set to the attempt of peeking at the Clipboard content as an image by calling ClipboardPeekImage.  If the Clipboard contains image data, the pass-by-reference boolean got is set true, and textBox1.Text is appended with a short image description.

Last, if an image was not 'got', ClipboardPeekString is called to retrieve a copy of the text on the Clipboard. textBox1.Text is appended with either the text on the Clipboard or a string indicating there is nothing on the Clipboard, there is no textual object on the Clipboard, or a description of the exception that occurred in calling Clipboard.GetText(TextDataFormat.UnicodeText).

buttonEncode_Click handles the user's request to encode the data on the Clipboard. It also first attempts to deal with Clipboard image data and then textual data if no image is present. This handler also calls ClipboardPeekImage and tests got. Here is the image encoding code for this handler:

C#
string s = ClipboardPeekImage(ref got);
if (got)
{
    var bs = Clipboard.GetImage();
    BitmapEncoder encoder;
    if (radioButton1.IsChecked == true)
    {
        encoder = new JpegBitmapEncoder();
        ((JpegBitmapEncoder)encoder).QualityLevel = 100;
    }
    else
        encoder = new PngBitmapEncoder();
    using (MemoryStream ms = new MemoryStream())
    {
        encoder.Frames.Add(BitmapFrame.Create(bs));
        encoder.Save(ms);
        s = Convert.ToBase64String(ms.ToArray());
        s = "!" + s; // leave non-Base64 marker for image

        if ((checkBox2.IsChecked == true) || (checkBox3.IsChecked == true))
            s = EncodeASCII85String(s);
    }
}
...
if (got)
    Clipboard.SetText(s);
textBox1.Text += Clipboard.GetText();  // empty string if no text

In this case the image is collected as a BitmapSource and encoded as either a Jpeg image or a Png image before conversion to a Base64 string. The thing to note is that the string is prefixed with a '!' character, which isn't in the Base64 codeset, to mark it as a Base64 image string as opposed to a Base64 text string. This is important later when we decode Clipboard contents.

The choice of Jpg or Png is selected by the RadioButton's on the UI. Jpg is the default since it produces smaller strings but is sometimes less faithful in maintaining content. Of the two images below:

Jpg Giraffe Png Giraffe

the PNG image on the right is closer to the original image copied to the Clipboard.

The CheckBox controls are then tested and the encode string is updated by ASCII85 and/or RotN encoding (s = EncodeASCII85String(s)) if either encoding is selected.

Once the final encoding is created, it is set back on the Clipboard by Clipboard.SetText(s) and shown in textBox1.

On the decode side, Clipboard contents are decoded in reverse order of the encoding steps. The first stage is to decode a RotN encoding when the RotN CheckBox is checked. RotN decoding is accomplished by finding the replacement character N moves earlier in the alphabet or equivalently by 26 - N moves further on in the alphabet if we wrap the end of the alphabet to the beginning (see Private Constants in MainWindow.xaml.cs). This is why EncodeDecodeRotNString can handle both encoding and decoding:

C#
private string EncodeDecodeRotNString(string s, int N)
{
    StringBuilder sb = new StringBuilder(s);

    int at = 0, idx;
    foreach (char c in s)
    {
        if ((idx = UpperRot.IndexOf(c)) != -1)
            sb[at] = LowerRot[idx + N];
        else if ((idx = LowerRot.IndexOf(c)) != -1)
            sb[at] = UpperRot[idx + N];
        at++;
    }
    return sb.ToString();
}

For encoding, argument N is the value from textBox3, the small TextBox with a ScrollBar to its right. For decoding, the N argument is 26 - textBox3's value. Note we swap upper and lower case during encoding or decoding for further obfuscation.

Points of Interest

Rather than give a list of reference related to this project, I will point out just two links. The single biggest aid I used is at http://www.codinghorror.com/blog/2005/10/c-implementation-of-ascii85.html.  I thank Jeff Atwood who, in 2005, implemented the version of ASCII85 used here with some changes. See the source file Ascii85.cs.

I've mentioned my beloved Adobe Photoshop 7.0 before in Tip 440706. I've been betrayed yet again. But, I have found the reason copying large images from Photoshop did not show up correctly for external Clipboard access. There is a registry entry needed to overcome a size limit as discussed at http://forums.adobe.com/message/1637186. Adding the DWORD value of 0 named MaxClipSize to HKEY_CURRENT_USER\Software\Adobe\Photoshop\7.0 (your version may vary) fixes this limit on copying a Select All selection to the Clipboard.

UI Update

I can't believe I was that much of a novice just 2 1/2 years ago.  The application definitely had some usability issues.  Hopefully the update in the link above fixes most of them.  For one, I've added a double-click handler so the full content of the TextBox can be easily selected for copy.  I've also added ScrollBars for those cases (encode clipboard images) where more than one line is needed.  I still don't know how Base64 encoding can lead to line breaks but cut and paste and encode / decode seem to work for small pictures.  Hope this fixes any problems you may have encountered.

History

Submitted to CodeProject 19 September 2012.

Updated April 2015.

License

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