123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="utf-8">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
- <meta name="description" content="steganography, cryptography, png, webp, hack, encrypt, decrypt">
- <meta name="author" content="bzt">
- <!-- o
- o hi, hacker!
- ooo -->
- <title>Steganography</title>
- <link href="logo.png" rel="shortcut icon">
- <style>
- input, textarea { font-family: monospace,fixed; }
- #url, #input { width:48%; }
- input[type="password"] { width:100%; }
- textarea { width:100%; height:100%; min-height:256px; }
- button { width:33%; }
- table { width:100%; }
- small { opacity:50%; }
- a[download] { display:none; }
- #jserr { color:white; background:red; font-weight:bold; font-size: 150%; text-align:center; padding: 32px; }
- </style>
- </head>
- <body>
- <h1>Steganography</h1>
- <div id="jserr">Please enable JavaScript</div>
- <script>document.getElementById("jserr").style.display = "none";</script>
- <p>No ads. No logs. No telemetry. No server components. Maximum privacy. It's <a href="https://gitlab.com/bztsrc/stegano">Open Source</a>, so you can even run it on your own site or locally if you don't trust gitlab (the wasm file works with a "file:///" URL in Firefox, but precompiled portable executables for Windows and Linux are also available in the <a href="https://gitlab.com/bztsrc/stegano/-/tree/main/bin">repo</a>).</p>
- <table>
- <tr><td>Image<sup>1</sup></td><td width="100%"><input id="url" onchange="geturl()" placeholder="https://..."> <input type="file" id="input" onchange="getfile()"></td></tr>
- <tr><td>Password<sup>2</sup></td><td><input type="password" id="pass" maxlength="255"></td></tr>
- <tr><td></td><td align="center"><button onclick="load()">Load</button> <button onclick="save()">Save<sup>3</sup></button></td></tr>
- <tr><td>Message</td><td><textarea id="message"></textarea><br>Capacity <span id="capacity">0</span> bytes.</td></tr>
- </table>
- <small>
- <sup>1</sup> - Input image can be either an URL or a local file in WEBP, PNG, GIF or JPEG format<br>
- <sup>2</sup> - password is optional. If given, message is encrypted with military grade AES<br>
- <sup>3</sup> - the resulting image is saved in WEBP format<br>
- </small>
- <br><img src="data:type/png;base64,iVBORw0KGgoAAAANSUhEUgAAAH8AAAAzAgMAAADDST+XAAAADFBMVEUAAAC8AAC9AAC+AADyLdeuAAAAAXRSTlMAQObYZgAAAn5JREFUOMt9lbtuU0EQhidrcQQrZCGq4OooitDRiooOV34EiqShSovFQwymsUzjIAWJisUyaL2JIosiRZQiT0PhhwDmsru248tK5+Ld7+zM/DM7Btg33C/Yvx5vkB4m7hg/vwKc7QO+9QCOCbBrs5Plq6fFww3gPL/cRnaj2QB+5xfntwODYooDgJquzpwjYt56Gz8lwAaJlKcdo5YpQ0DawYuLAPIxXJy+rfDR6YlBlwGrFgwKQB9YWgsMoKwHF0kfgIqpuAZAiiXQC1lmILQScLUELM0w8EoA0hq70Ke5ewL6aoF31CAUcLAggLd1BKDoEcBiBr4vxJEMVCQk5+KFRBIknbQ2z0Bw4kgPFgL4KgHeJcD3BUgysHz0ETvStBRQsa6S0qsA3Sh3l7aUA1/tub3893cVCN1kQQGSaEqhSPIV8Ko2z4wVCNAqihCAxQKgAuSB51h9O3KOJOwZVUdKpgLsmOhvQpuBqSEjClACpmuABDFnI5JMKQcF5pJB71LVoZTssl5ophPjvcG4FeDY+dYzkNZzthcrO9ANLZSDZUq2ve0V4HE+qwBPoNRLRwwzJXqnXDUKZEdEfYu1yS6qCyZmRxQYe5NdVBeMnuQyxmhyKt4AbGkfHg9ysqcKiIYzE/1ITzWC1mOyAIZbyiJM4g+to2uUqhTHZVQfz+rGTl8iwrBunnV47z9YwuO4nmM9irYZNE/v6omNuQfqoaHnaDJ8bb+cN5+PAY8GrgAug6MBeju2ZnRohkdYgANfuultnKkWN/F6FjPgkgXoPmyfPQ0uLPvxg4HrG2wAs7FscFU6+kaHPuHZPu4GLjB1zV2jiu/fhb1/I+34YeXXfzyvR6xFYz9TAAAAAElFTkSuQmCC" alt="GPLv3+">
- <script src="stegano.js"></script>
- <script>
- var imgdata = new Uint8Array();
- try {
- var url = document.location.href.split('?')[1];
- if(url && url != "" && url != undefined) {
- document.getElementById("url").value = url;
- geturl();
- }
- }catch(e){}
- function calccap() {
- var getcapacity = Module.cwrap("getcapacity", "number", [ "number", "number" ]);
- if(imgdata.length < 1) { alert("No input image."); return; }
- const buf = Module._malloc(imgdata.length);
- Module.HEAPU8.set(imgdata, buf);
- var cap = getcapacity(buf, imgdata.length);
- Module._free(buf);
- document.getElementById("capacity").innerText = cap.toLocaleString('en-US');
- document.getElementById("message").maxLength = cap;
- document.getElementById("message").value = "";
- }
- function load() {
- var decode = Module.cwrap("decode", "number", [ "number", "number", "number", "number", "number", "number" ]);
- var cap = document.getElementById("message").maxLength;
- var pin = new TextEncoder().encode(document.getElementById("pass").value);
- document.getElementById("message").value = "";
- if(imgdata.length < 1 || cap < 16) { alert("No input image."); return; }
- const buf = Module._malloc(imgdata.length);
- const pas = Module._malloc(pin.length+1);
- const msg = Module._malloc(cap);
- Module.HEAPU8.set(imgdata, buf);
- Module.HEAPU8.set(pin, pas);
- var len = decode(buf, imgdata.length, pas, pin.length, msg, cap);
- if(len > 0) {
- const view = new Uint8Array(Module.HEAPU8.buffer,msg,len);
- document.getElementById("message").value = new TextDecoder().decode(view);
- } else
- alert("Probably no message in image or bad password.");
- Module._free(buf);
- Module._free(pas);
- Module._free(msg);
- document.getElementById("pass").value = "";
- }
- function save() {
- var encode = Module.cwrap("encode", "number", [ "number", "number", "number", "number", "number", "number" ]);
- var txt = new TextEncoder().encode(document.getElementById("message").value);
- var pin = new TextEncoder().encode(document.getElementById("pass").value);
- if(imgdata.length < 1) { alert("No input image."); return; }
- if(txt.length < 1) { alert("No message."); return; }
- const buf = Module._malloc(128*1024*1024); /* must match MAXIMGSIZE in stegano.h */
- const pas = Module._malloc(pin.length+1);
- const msg = Module._malloc(txt.length+32);
- Module.HEAPU8.set(imgdata, buf);
- Module.HEAPU8.set(pin, pas);
- Module.HEAPU8.set(txt, msg);
- var len = encode(buf, imgdata.length, pas, pin.length, msg, txt.length);
- if(len > 0) {
- const view = new Uint8Array(Module.HEAPU8.buffer,buf,len);
- var blob = new Blob([view], { type: "image/webp" });
- var url = window.URL.createObjectURL(blob);
- var a = document.createElement("A");
- a.href = url;
- a.download = "stegano.webp";
- document.body.appendChild(a);
- a.click();
- a.remove();
- window.URL.revokeObjectURL(url);
- } else
- alert("Unable to generate output image.");
- Module._free(buf);
- Module._free(pas);
- Module._free(msg);
- document.getElementById("pass").value = "";
- }
- function geturl() {
- fetch(document.getElementById("url").value).then((response) => {
- if(response.ok) response.arrayBuffer().then((buf) => { imgdata = new Uint8Array(buf); calccap(); });
- })
- .catch((error) => alert("Unable to get url\n" + error));
- }
- function getfile() {
- var input=document.getElementById("input");
- if(input.files.length<1) {
- alert("No file given.");
- } else {
- var reader = new FileReader();
- reader.onloadend = function() { imgdata = new Uint8Array(reader.result); calccap(); };
- reader.readAsArrayBuffer(input.files[0]);
- }
- }
- </script>
- </body>
- </html>
|