Skip to main content

da Vinci of the 21st Century

According to many sources, Leonardo Da Vinci is known for hiding secret codes and messages in his art work. In the modern era, digital canvases and images have a greater role to play.

An image of width w and height h contains w x h pixels. Changing the RGB values by a small value would not be detectable to naked eye. In this blog post, let me show you how to encrypt and decrypt messages using this principle. We'll do both encryption and decryption using JavaScript.

To get started with, I downloaded a very nice picture of Mona Lisa from Wikipedia (. I also created an image with black text in a white background, which I shall not show here (message.jpg).


Next, I setup a good HTML platform to run back to back JavaScript commands, which would automatically load all the images I need. To avoid CORS issue, I have been running a SimpleHTTPServer to open up the webpage.

<html>
<body>
<img src="725px-Mona_Lisa,_by_Leonardo_da_Vinci,_from_C2RMF_retouched.jpg" id="original" style="display: none"/>
<img src="message.jpg" id="message" style="display: none" />
<img src="encryptedTextHere.jpg" id="encrypted" style="display: none" />
<canvas id="myCanvas" width="725" height="1080" style="border:1px solid #d3d3d3;">

<script>

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");

</script>
</body>
</html>

Note that encryptedTextHere.jpg does not exist as of now, but that can be ignored. That is the location where I intent to save the encrypted file.

Encrypting


Now that the platform is up, let's open the Chrome Developer Console (press CTRL+Shift+J and click on Console tab). Let us read both the images into canvas image data arrays. Then, in the original Mona Lisa image, wherever the pixels matches with the message image, let us increment the RGB pixels by 1 value. Ignore all the white spaces. The following code takes care of that.



var original = document.getElementById("original");
var message = document.getElementById("message");
ctx.drawImage(original, 0, 0);
var originalArray = ctx.getImageData(0, 0, c.width, c.height);
ctx.drawImage(message, 0, 0);
var messageArray = ctx.getImageData(0, 0, c.width, c.height);
for(var i=0;i<originalArray.data.length;i+=4){
    if(messageArray.data[i] + messageArray.data[i+1] + messageArray.data[i+2] + messageArray.data[i+3] !== 255*4){ // ignoring white
        originalArray.data[i] += 1;
        originalArray.data[i+1] += 1;
        originalArray.data[i+2] += 1;
    }
}
ctx.putImageData(originalArray, 0, 0);
Once the image is drawn, save the image as encryptedTextHere.jpg. You have succesfully encrypted your message into the image. If you observe the image, it is hard (or impossible) to say what message is encrypted with your naked eye.

Decrypting

Both the original image and the encrypted image are required to find the hidden text. Since we just added a pixel at every point where there is a corresponding pixel in the message image existed, we could simply reverse the process to get some value at the pixels where the message existed. To get a better clarity, multiply that with a value of 100. The following code does the same. Leave every fourth pixel (opacity) at the maximum value of 255.



var original = document.getElementById("original");
var encrypted = document.getElementById("encrypted");
ctx.drawImage(original, 0, 0);
var originalArray = ctx.getImageData(0, 0, c.width, c.height);
ctx.drawImage(encrypted, 0, 0);
var encryptedArray = ctx.getImageData(0, 0, c.width, c.height);
for(var i=0;i<originalArray.data.length;i++){
    encryptedArray.data[i] = (encryptedArray.data[i] - originalArray.data[i]) * 100;
    if((i+1)%4 === 0) // transparency part
        encryptedArray.data[i] = 255;
}
ctx.putImageData(encryptedArray, 0, 0);
You now have a pretty neat tool in your hand to encrypt and decrpy messages. You may tweak the technique a bit to store encrypted data in the way you desire. Some things are best kept secrets. Cheers!

Comments

Popular posts from this blog

How to Create your own Ad Blocker Chrome Extension

Not very long ago, I read an article stating that Google banned advertisement blockers from its stores. There are several websites which does not let you in if you have an Ad blocker extension installed on your browser. I have not investigated on how these websites detect that, nor do I know whether our own version of advertisement blocker would be immune to that. But, isn't it fun to build something like this on our own? As the first step, I found a random website that has a Google Ad. I right clicked on the Google Ad and clicked on Inspect button. As I moved up the Elements inspector, I found that the id of the advertisement starts with "google_ads_". Therefore, I opened the console and typed in the following command: div = document.querySelector('[id^="google_ads_"]') This selected the div  that contained the advertisement. I went ahead and typed in the following command that would remove the div from the page. div.parentElement.remove...

Turning your phone into a virtual-joystick

Update: I kept working on this and I have released it as a package for Windows, Linux and macOS. Check it out: https://github.com/zenineasa/joystick/releases/tag/v1.0.0 -- During the days when I was pursying my master's programme, my friends and I used to occasionally go to a classroom in the university, turn on a projector, connect devices like Nintento Switch or Gaming computers and loads of joysticks, and play different simple multiplayer games; MarioKart was my favourite. From time-to-time, when I get together with people, I ponder that it would be a good idea if I bought such devices. Indeed, I do have a laptop, which could easily run such games; SuperTuxKart is similar enough to MarioKart and it can run on Linux, Windows and Mac. However, I do not have joysticks with me at the moment. Therefore, I think it would be a good idea if I simply worked on a project that would enable using our phones as joysticks. From a high-level, the plan is to host APIs on a NodeJS server that wo...

How to remove Blogger (or any free blogging platform) credits from the footer

I am not sure if removing the footer credits is legal or not, but I just wanted to try doing it. As I searched the internet, I found several pages describing how it could be done by making some adjustments in CSS. However, I could not find an article which uses simple JavaScript commands to do the same. So, I decided the write this. As you can see now, my footer does have Powered By Blogger credit signature. I am intending on keeping it that way until I am sure that removing it would not get me into any legal issues. I am just writing this article for the educational purposes. Right click on the Powered By Blogger  button and click on Inspect to have Chrome Developer tools loaded with the div that holds the credit content. You can see that the element should have a content similar to the following. Notice that the div is having a class value blogger . We can use this to our advantage. <div class="blogger"> <a href="https://www.blogger.com...