Steganography

is the art and science of writing hidden messages in such a way that no one, apart from the sender and intended recipient, suspects the existence of the message, a form of security through obscurity.Wikipedia
hi

How does this work?

Normal images are rendered as a grid of pixels where each pixel has 24bits, 8 for the red channel, 8 for the green, and 8 for the blue (RGB). This allows 256 possible values for each color channel for a total of 256**3 ~ 16.7 million colors.

However, the human eye cannot perceive this many colors. In fact, the human eye can't notice a difference if the 2 most insignifcant bits of each channel were replaced with random noise! We can abuse this fact and replace the 2 most insignificant bits of each channel with actual data we want to transmit with the image.

The example here uses the HTML5 canvas tag to do operations on image bitmap data. It stores one character of the message inside 1.33 pixels. Images are saved as png so that compression does not mess with the data.

Encode/decode functions:

function textToImageData(text, imgd) {
    text = "@!$" + text + String.fromCharCode(0);
    var imageidx = 0;
    for (var i = 0; i < text.length; i++) {
        var charCode = text.charCodeAt(i);
        imgd.data[imageidx] = (imgd.data[imageidx] & (~3)) | (charCode & 3);
        imageidx++;
        if (imageidx & 3 == 3) {
            imageidx++;
        }
        imgd.data[imageidx] = (imgd.data[imageidx] & (~3)) | ((charCode >> 2) & 3);
        imageidx++;
        if (imageidx & 3 == 3) {
            imageidx++;
        }
        imgd.data[imageidx] = (imgd.data[imageidx] & (~3)) | ((charCode >> 4) & 3);
        imageidx++;
        if (imageidx & 3 == 3) {
            imageidx++;
        }
        imgd.data[imageidx] = (imgd.data[imageidx] & (~3)) | ((charCode >> 6) & 3);
        imageidx++;
        if (imageidx & 3 == 3) {
            imageidx++;
        }
    }
    return imgd;
}

function textFromImage(imgd) {
    var text = "";
    for (var i = 0; i < imgd.width*imgd.height*4;) {
        var charCode = 0;
        charCode |= imgd.data[i] & 3;
        i++;
        if (i & 3 == 3) {
            i++;
        }
        charCode |= (imgd.data[i] & 3) << 2;
        i++;
        if (i & 3 == 3) {
            i++;
        }
        charCode |= (imgd.data[i] & 3) << 4;
        i++;
        if (i & 3 == 3) {
            i++;
        }
        charCode |= (imgd.data[i] & 3) << 6;
        i++;
        if (i & 3 == 3) {
            i++;
        }
        if (charCode == 0) {
            break;
        }
        text += String.fromCharCode(charCode);
    }
    if (text.substring(0,3) != "@!$") {
        return "";
    }
    return text.substring(3);
}
Powered By Filepicker.io