Skip to content

Commit 1d7abb3

Browse files
committed
Merge branch 'master' of github.com:tuseroni/stegano.js
2 parents 625f9d4 + 12bd386 commit 1d7abb3

File tree

3 files changed

+51
-19
lines changed

3 files changed

+51
-19
lines changed

README

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
a javascript and HTML based steganography encoder/decoder.
22
encoder.html takes a .png file as the cover and any file data file as the hidden data. the hidden data cannot be bigger than the width*the height of the cover image (in bytes)
3-
decoder.html takes a png with the name canvas.png (the ability to pick arbitrary files coming soon) and extracts the data from the image.
3+
decoder.html takes an encoded png selected by the user and extracts the data from the image.
44

55
the encoder uses a Pseudo-Random number generator seeded with a hash of a string which serves as the password. the same password must be used for decoding as was used for encoding.
66

77
requires Firefox (dont know the minimum version, but just best to have the latest)
88

99
still to do:
10-
. arbitrary data hidden inside audio files
11-
. arbitrary data hidden inside video files
12-
. clean up the page a bit (planning to move most of it to a webworker and use that to update a progress bar element, should also give a boost to performance and usability)
13-
. move a bunch of the code into a greasemonkey script (or BACK into a greasemonkey script)
14-
. make it work in chrome and maybe ie9 or 10
15-
. celebrate
10+
* arbitrary data hidden inside audio files
11+
* arbitrary data hidden inside video files
12+
* clean up the page a bit (planning to move most of it to a webworker and use that to update a progress bar element, should also give a boost to performance and usability)
13+
* move a bunch of the code into a greasemonkey script (or BACK into a greasemonkey script)
14+
* make it work in chrome and maybe ie9 or 10
15+
* celebrate
1616

1717
wish i could do:
18-
. use some other image format than png for the cover image, but all images are converted to png by the canvas tag
19-
. suggest a name for the download (i wish base64 uris had a filename hint optional part, something to tell the browser "try this filename when saving this file" so like (data:|foo.png;base64,data)
18+
* use some other image format than png for the cover image, but all images are converted to png by the canvas tag
19+
* suggest a name for the download (i wish base64 uris had a filename hint optional part, something to tell the browser "try this filename when saving this file" so like (data:|foo.png;base64,data)
2020

2121
credits:
2222
Chris McKenzie, his project:

decoder.html

+31-7
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,30 @@
11
<html>
22
<body>
3-
<img src="canvas2.png">
3+
<input type="file" id="img" accept="image/png">
4+
<button onclick="makeImg()">Decode It</button>
45
<script type="text/javascript">
56
var contextNode=null;
7+
var redIndicies=[];
8+
function makeImg()
9+
{
10+
var outerImg=document.getElementById("img");
11+
if(!outerImg.files[0])
12+
{
13+
return;
14+
}
15+
var imgdat=outerImg.files[0];
16+
var reader = new FileReader();
17+
reader.onload=function(event)
18+
{
19+
var img=new Image;
20+
img.onload=function()
21+
{
22+
doThings(this);
23+
}
24+
img.src=event.target.result;
25+
}
26+
reader.readAsDataURL(imgdat);
27+
}
628
function base64_encode (data,isutf8) {
729
// Encodes string using MIME base64 algorithm
830
//
@@ -53,11 +75,13 @@
5375
var randnum=Math.floor(rng()*newData.length);
5476
var redIndex=randnum-(randnum%4);
5577
var name="";
78+
5679
if(newData[redIndex]==-1)
5780
{
5881
return getName(rng,imageData,newData,deletedbytes);
5982
}
6083
len=((imageData[redIndex] & 7)<<5 | (imageData[redIndex+1] & 3)<<3 |(imageData[redIndex+2] & 7));
84+
//redIndicies.push(redIndex);
6185
newData[redIndex]=-1;
6286
deletedbytes++;
6387
for(var i=0;i<len;i++)
@@ -70,6 +94,7 @@
7094
i--;
7195
continue;
7296
}
97+
//redIndicies.push(redIndex);
7398
byte=((imageData[redIndex] & 7)<<5 | (imageData[redIndex+1] & 3)<<3 |(imageData[redIndex+2] & 7));
7499
name+=String.fromCharCode(byte);
75100
newData[redIndex]=-1;
@@ -89,6 +114,7 @@
89114
i--;
90115
continue;
91116
}
117+
//redIndicies.push(redIndex);
92118
byte=((imageData[redIndex] & 7)<<5 | (imageData[redIndex+1] & 3)<<3 |(imageData[redIndex+2] & 7));
93119
len|=byte<<(i*8);
94120
newData[redIndex]=-1;
@@ -189,12 +215,8 @@
189215
} (Array.prototype.slice.call(arguments)));
190216
};
191217

192-
function doThings()
193-
{
194-
if(!contextNode)
218+
function doThings(img)
195219
{
196-
return;
197-
}
198220
var canvas = null,
199221
ctx = null,
200222
canvas = document.createElement("canvas");
@@ -203,7 +225,6 @@
203225
var b = document.getElementsByTagName("body")[0];
204226
b.appendChild(canvas);
205227
ctx = canvas.getContext("2d");
206-
var img = contextNode;
207228
// apply the width and height to the canvas element
208229
canvas.width = img.width;
209230
canvas.height = img.height;
@@ -238,6 +259,7 @@
238259
retObj=getBodyLength(rng,imageData,newData,deletedbytes);
239260
newData=retObj.newData;
240261
len=retObj["len"];
262+
241263
for(var i = 0; i < len; i++){
242264
var randnum=Math.floor(rng()*newData.length);
243265
var redIndex=randnum-(randnum%4);
@@ -247,11 +269,13 @@
247269
i--;
248270
continue;
249271
}
272+
//redIndicies.push(redIndex);
250273
byte=((imageData[redIndex] & 7)<<5 | (imageData[redIndex+1] & 3)<<3 |(imageData[redIndex+2] & 7));
251274
body+=String.fromCharCode(byte);
252275
newData[redIndex]=-1;
253276
deletedbytes++;
254277
}
278+
//alert(redIndicies);
255279
var base64string=base64_encode(body,true);
256280
url="data:application/octet-stream;base64,"+base64string;
257281
var theif=document.createElement("iframe");

encoder.html

+11-3
Original file line numberDiff line numberDiff line change
@@ -180,11 +180,17 @@
180180
var width = canvas.width;
181181
var pass=prompt("please enter a password");
182182
var rng = new Alea(pass);
183+
var redIndicies=[];
183184
for(var i = 0; i<length; i++)
184185
{
185186
newData[i]=i;
186187
}
187188
var bytes=String.fromCharCode(nameLen)+fileName+getLengthInChars(fileLen)+file;
189+
if(imageData.length/4<bytes.length)
190+
{
191+
alert("innerFile too big")
192+
return;
193+
}
188194
for(var i = 0; i <= bytes.length; i++){
189195
var randnum=Math.floor(rng()*newData.length);
190196
var redIndex=randnum-(randnum%4);
@@ -193,19 +199,21 @@
193199
i--;
194200
continue;
195201
}
202+
//redIndicies.push(redIndex);
196203
imageData[redIndex]=((imageData[redIndex] & (~7)) | ((bytes.charCodeAt(i)>>5)&7))
197204
imageData[redIndex+1]=((imageData[redIndex+1] & (~3)) | ((bytes.charCodeAt(i)>>3)&3))
198205
imageData[redIndex+2]=((imageData[redIndex+2] & (~7)) | ((bytes.charCodeAt(i))&7))
199206
newData[redIndex]=-1;
200207
}
208+
//alert(redIndicies);
201209
image.data=imageData;
202210
ctx.putImageData(image,0,0);
203211
canvas.style.display="";
204212
}
205213
</script>
206-
<body onload="doThings()">
207-
<p>select Outer Image:</p>
208-
<p><input type="file" id="img"></p>
214+
<body>
215+
<p>select Outer Image(PNG format):</p>
216+
<p><input type="file" id="img" accept="image/*"></p>
209217
<p>select innerFile:</p>
210218
<p><input type="file" id="file"></p>
211219
<button onclick="makeImg()">Do it!</button>

0 commit comments

Comments
 (0)