initial commit after rename
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="net.chaoswebs.snow10">
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.AppCompat.NoActionBar">
|
||||
<activity android:name=".MainActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
|
@ -0,0 +1,8 @@
|
|||
The MIT License (MIT)
|
||||
Copyright (c) 2017 Kevin Froman
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,36 @@
|
|||
# Snow2
|
||||
|
||||
Obfuscate & Encrypt Text as White-Space
|
||||
|
||||
Demo: [https://ChaosWebs.net/snow2](https://chaoswebs.net/snow2/)
|
||||
|
||||
![snow image](snow.jpg)
|
||||
|
||||
# About
|
||||
|
||||
Snow2 is a web app inspired by the [original snow program](http://darkside.com.au/snow/) to use whitespace/zero-width characters to obfuscate messages within the whitespace of other content.
|
||||
|
||||
# License
|
||||
|
||||
MIT license, see LICENSE file.
|
||||
|
||||
# Warnings
|
||||
|
||||
* No steganography is perfect, your message may be discovered especially by skilled adversaries.
|
||||
* Some text editors (like vim) show zero width characters
|
||||
* Some clients/places may strip whitespace characters
|
||||
* Use encryption if you really need to protect your messages. Use a good password but keep in mind that no encryption is perfect (Snow2 uses cryptojs AES)
|
||||
* It is best to save the site offline to avoid your messages being intercepted by possible malicious code sent from (my) web server
|
||||
* The larger your message, the more obvious it is that it is there.
|
||||
|
||||
# Roadmap (to do)
|
||||
|
||||
* Ability to automatically spread/retrieve message content into paragraphs of "cover" text
|
||||
|
||||
* CLI version
|
||||
|
||||
* Android app
|
||||
|
||||
# Contributing
|
||||
|
||||
Feel free to make a pull request if you feel that you have improved the software.
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
CryptoJS v3.1.2
|
||||
code.google.com/p/crypto-js
|
||||
(c) 2009-2013 by Jeff Mott. All rights reserved.
|
||||
code.google.com/p/crypto-js/wiki/License
|
||||
*/
|
||||
var CryptoJS=CryptoJS||function(u,p){var d={},l=d.lib={},s=function(){},t=l.Base={extend:function(a){s.prototype=this;var c=new s;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}},
|
||||
r=l.WordArray=t.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=p?c:4*a.length},toString:function(a){return(a||v).stringify(this)},concat:function(a){var c=this.words,e=a.words,j=this.sigBytes;a=a.sigBytes;this.clamp();if(j%4)for(var k=0;k<a;k++)c[j+k>>>2]|=(e[k>>>2]>>>24-8*(k%4)&255)<<24-8*((j+k)%4);else if(65535<e.length)for(k=0;k<a;k+=4)c[j+k>>>2]=e[k>>>2];else c.push.apply(c,e);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<<
|
||||
32-8*(c%4);a.length=u.ceil(c/4)},clone:function(){var a=t.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],e=0;e<a;e+=4)c.push(4294967296*u.random()|0);return new r.init(c,a)}}),w=d.enc={},v=w.Hex={stringify:function(a){var c=a.words;a=a.sigBytes;for(var e=[],j=0;j<a;j++){var k=c[j>>>2]>>>24-8*(j%4)&255;e.push((k>>>4).toString(16));e.push((k&15).toString(16))}return e.join("")},parse:function(a){for(var c=a.length,e=[],j=0;j<c;j+=2)e[j>>>3]|=parseInt(a.substr(j,
|
||||
2),16)<<24-4*(j%8);return new r.init(e,c/2)}},b=w.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var e=[],j=0;j<a;j++)e.push(String.fromCharCode(c[j>>>2]>>>24-8*(j%4)&255));return e.join("")},parse:function(a){for(var c=a.length,e=[],j=0;j<c;j++)e[j>>>2]|=(a.charCodeAt(j)&255)<<24-8*(j%4);return new r.init(e,c)}},x=w.Utf8={stringify:function(a){try{return decodeURIComponent(escape(b.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data");}},parse:function(a){return b.parse(unescape(encodeURIComponent(a)))}},
|
||||
q=l.BufferedBlockAlgorithm=t.extend({reset:function(){this._data=new r.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=x.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var c=this._data,e=c.words,j=c.sigBytes,k=this.blockSize,b=j/(4*k),b=a?u.ceil(b):u.max((b|0)-this._minBufferSize,0);a=b*k;j=u.min(4*a,j);if(a){for(var q=0;q<a;q+=k)this._doProcessBlock(e,q);q=e.splice(0,a);c.sigBytes-=j}return new r.init(q,j)},clone:function(){var a=t.clone.call(this);
|
||||
a._data=this._data.clone();return a},_minBufferSize:0});l.Hasher=q.extend({cfg:t.extend(),init:function(a){this.cfg=this.cfg.extend(a);this.reset()},reset:function(){q.reset.call(this);this._doReset()},update:function(a){this._append(a);this._process();return this},finalize:function(a){a&&this._append(a);return this._doFinalize()},blockSize:16,_createHelper:function(a){return function(b,e){return(new a.init(e)).finalize(b)}},_createHmacHelper:function(a){return function(b,e){return(new n.HMAC.init(a,
|
||||
e)).finalize(b)}}});var n=d.algo={};return d}(Math);
|
||||
(function(){var u=CryptoJS,p=u.lib.WordArray;u.enc.Base64={stringify:function(d){var l=d.words,p=d.sigBytes,t=this._map;d.clamp();d=[];for(var r=0;r<p;r+=3)for(var w=(l[r>>>2]>>>24-8*(r%4)&255)<<16|(l[r+1>>>2]>>>24-8*((r+1)%4)&255)<<8|l[r+2>>>2]>>>24-8*((r+2)%4)&255,v=0;4>v&&r+0.75*v<p;v++)d.push(t.charAt(w>>>6*(3-v)&63));if(l=t.charAt(64))for(;d.length%4;)d.push(l);return d.join("")},parse:function(d){var l=d.length,s=this._map,t=s.charAt(64);t&&(t=d.indexOf(t),-1!=t&&(l=t));for(var t=[],r=0,w=0;w<
|
||||
l;w++)if(w%4){var v=s.indexOf(d.charAt(w-1))<<2*(w%4),b=s.indexOf(d.charAt(w))>>>6-2*(w%4);t[r>>>2]|=(v|b)<<24-8*(r%4);r++}return p.create(t,r)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}})();
|
||||
(function(u){function p(b,n,a,c,e,j,k){b=b+(n&a|~n&c)+e+k;return(b<<j|b>>>32-j)+n}function d(b,n,a,c,e,j,k){b=b+(n&c|a&~c)+e+k;return(b<<j|b>>>32-j)+n}function l(b,n,a,c,e,j,k){b=b+(n^a^c)+e+k;return(b<<j|b>>>32-j)+n}function s(b,n,a,c,e,j,k){b=b+(a^(n|~c))+e+k;return(b<<j|b>>>32-j)+n}for(var t=CryptoJS,r=t.lib,w=r.WordArray,v=r.Hasher,r=t.algo,b=[],x=0;64>x;x++)b[x]=4294967296*u.abs(u.sin(x+1))|0;r=r.MD5=v.extend({_doReset:function(){this._hash=new w.init([1732584193,4023233417,2562383102,271733878])},
|
||||
_doProcessBlock:function(q,n){for(var a=0;16>a;a++){var c=n+a,e=q[c];q[c]=(e<<8|e>>>24)&16711935|(e<<24|e>>>8)&4278255360}var a=this._hash.words,c=q[n+0],e=q[n+1],j=q[n+2],k=q[n+3],z=q[n+4],r=q[n+5],t=q[n+6],w=q[n+7],v=q[n+8],A=q[n+9],B=q[n+10],C=q[n+11],u=q[n+12],D=q[n+13],E=q[n+14],x=q[n+15],f=a[0],m=a[1],g=a[2],h=a[3],f=p(f,m,g,h,c,7,b[0]),h=p(h,f,m,g,e,12,b[1]),g=p(g,h,f,m,j,17,b[2]),m=p(m,g,h,f,k,22,b[3]),f=p(f,m,g,h,z,7,b[4]),h=p(h,f,m,g,r,12,b[5]),g=p(g,h,f,m,t,17,b[6]),m=p(m,g,h,f,w,22,b[7]),
|
||||
f=p(f,m,g,h,v,7,b[8]),h=p(h,f,m,g,A,12,b[9]),g=p(g,h,f,m,B,17,b[10]),m=p(m,g,h,f,C,22,b[11]),f=p(f,m,g,h,u,7,b[12]),h=p(h,f,m,g,D,12,b[13]),g=p(g,h,f,m,E,17,b[14]),m=p(m,g,h,f,x,22,b[15]),f=d(f,m,g,h,e,5,b[16]),h=d(h,f,m,g,t,9,b[17]),g=d(g,h,f,m,C,14,b[18]),m=d(m,g,h,f,c,20,b[19]),f=d(f,m,g,h,r,5,b[20]),h=d(h,f,m,g,B,9,b[21]),g=d(g,h,f,m,x,14,b[22]),m=d(m,g,h,f,z,20,b[23]),f=d(f,m,g,h,A,5,b[24]),h=d(h,f,m,g,E,9,b[25]),g=d(g,h,f,m,k,14,b[26]),m=d(m,g,h,f,v,20,b[27]),f=d(f,m,g,h,D,5,b[28]),h=d(h,f,
|
||||
m,g,j,9,b[29]),g=d(g,h,f,m,w,14,b[30]),m=d(m,g,h,f,u,20,b[31]),f=l(f,m,g,h,r,4,b[32]),h=l(h,f,m,g,v,11,b[33]),g=l(g,h,f,m,C,16,b[34]),m=l(m,g,h,f,E,23,b[35]),f=l(f,m,g,h,e,4,b[36]),h=l(h,f,m,g,z,11,b[37]),g=l(g,h,f,m,w,16,b[38]),m=l(m,g,h,f,B,23,b[39]),f=l(f,m,g,h,D,4,b[40]),h=l(h,f,m,g,c,11,b[41]),g=l(g,h,f,m,k,16,b[42]),m=l(m,g,h,f,t,23,b[43]),f=l(f,m,g,h,A,4,b[44]),h=l(h,f,m,g,u,11,b[45]),g=l(g,h,f,m,x,16,b[46]),m=l(m,g,h,f,j,23,b[47]),f=s(f,m,g,h,c,6,b[48]),h=s(h,f,m,g,w,10,b[49]),g=s(g,h,f,m,
|
||||
E,15,b[50]),m=s(m,g,h,f,r,21,b[51]),f=s(f,m,g,h,u,6,b[52]),h=s(h,f,m,g,k,10,b[53]),g=s(g,h,f,m,B,15,b[54]),m=s(m,g,h,f,e,21,b[55]),f=s(f,m,g,h,v,6,b[56]),h=s(h,f,m,g,x,10,b[57]),g=s(g,h,f,m,t,15,b[58]),m=s(m,g,h,f,D,21,b[59]),f=s(f,m,g,h,z,6,b[60]),h=s(h,f,m,g,C,10,b[61]),g=s(g,h,f,m,j,15,b[62]),m=s(m,g,h,f,A,21,b[63]);a[0]=a[0]+f|0;a[1]=a[1]+m|0;a[2]=a[2]+g|0;a[3]=a[3]+h|0},_doFinalize:function(){var b=this._data,n=b.words,a=8*this._nDataBytes,c=8*b.sigBytes;n[c>>>5]|=128<<24-c%32;var e=u.floor(a/
|
||||
4294967296);n[(c+64>>>9<<4)+15]=(e<<8|e>>>24)&16711935|(e<<24|e>>>8)&4278255360;n[(c+64>>>9<<4)+14]=(a<<8|a>>>24)&16711935|(a<<24|a>>>8)&4278255360;b.sigBytes=4*(n.length+1);this._process();b=this._hash;n=b.words;for(a=0;4>a;a++)c=n[a],n[a]=(c<<8|c>>>24)&16711935|(c<<24|c>>>8)&4278255360;return b},clone:function(){var b=v.clone.call(this);b._hash=this._hash.clone();return b}});t.MD5=v._createHelper(r);t.HmacMD5=v._createHmacHelper(r)})(Math);
|
||||
(function(){var u=CryptoJS,p=u.lib,d=p.Base,l=p.WordArray,p=u.algo,s=p.EvpKDF=d.extend({cfg:d.extend({keySize:4,hasher:p.MD5,iterations:1}),init:function(d){this.cfg=this.cfg.extend(d)},compute:function(d,r){for(var p=this.cfg,s=p.hasher.create(),b=l.create(),u=b.words,q=p.keySize,p=p.iterations;u.length<q;){n&&s.update(n);var n=s.update(d).finalize(r);s.reset();for(var a=1;a<p;a++)n=s.finalize(n),s.reset();b.concat(n)}b.sigBytes=4*q;return b}});u.EvpKDF=function(d,l,p){return s.create(p).compute(d,
|
||||
l)}})();
|
||||
CryptoJS.lib.Cipher||function(u){var p=CryptoJS,d=p.lib,l=d.Base,s=d.WordArray,t=d.BufferedBlockAlgorithm,r=p.enc.Base64,w=p.algo.EvpKDF,v=d.Cipher=t.extend({cfg:l.extend(),createEncryptor:function(e,a){return this.create(this._ENC_XFORM_MODE,e,a)},createDecryptor:function(e,a){return this.create(this._DEC_XFORM_MODE,e,a)},init:function(e,a,b){this.cfg=this.cfg.extend(b);this._xformMode=e;this._key=a;this.reset()},reset:function(){t.reset.call(this);this._doReset()},process:function(e){this._append(e);return this._process()},
|
||||
finalize:function(e){e&&this._append(e);return this._doFinalize()},keySize:4,ivSize:4,_ENC_XFORM_MODE:1,_DEC_XFORM_MODE:2,_createHelper:function(e){return{encrypt:function(b,k,d){return("string"==typeof k?c:a).encrypt(e,b,k,d)},decrypt:function(b,k,d){return("string"==typeof k?c:a).decrypt(e,b,k,d)}}}});d.StreamCipher=v.extend({_doFinalize:function(){return this._process(!0)},blockSize:1});var b=p.mode={},x=function(e,a,b){var c=this._iv;c?this._iv=u:c=this._prevBlock;for(var d=0;d<b;d++)e[a+d]^=
|
||||
c[d]},q=(d.BlockCipherMode=l.extend({createEncryptor:function(e,a){return this.Encryptor.create(e,a)},createDecryptor:function(e,a){return this.Decryptor.create(e,a)},init:function(e,a){this._cipher=e;this._iv=a}})).extend();q.Encryptor=q.extend({processBlock:function(e,a){var b=this._cipher,c=b.blockSize;x.call(this,e,a,c);b.encryptBlock(e,a);this._prevBlock=e.slice(a,a+c)}});q.Decryptor=q.extend({processBlock:function(e,a){var b=this._cipher,c=b.blockSize,d=e.slice(a,a+c);b.decryptBlock(e,a);x.call(this,
|
||||
e,a,c);this._prevBlock=d}});b=b.CBC=q;q=(p.pad={}).Pkcs7={pad:function(a,b){for(var c=4*b,c=c-a.sigBytes%c,d=c<<24|c<<16|c<<8|c,l=[],n=0;n<c;n+=4)l.push(d);c=s.create(l,c);a.concat(c)},unpad:function(a){a.sigBytes-=a.words[a.sigBytes-1>>>2]&255}};d.BlockCipher=v.extend({cfg:v.cfg.extend({mode:b,padding:q}),reset:function(){v.reset.call(this);var a=this.cfg,b=a.iv,a=a.mode;if(this._xformMode==this._ENC_XFORM_MODE)var c=a.createEncryptor;else c=a.createDecryptor,this._minBufferSize=1;this._mode=c.call(a,
|
||||
this,b&&b.words)},_doProcessBlock:function(a,b){this._mode.processBlock(a,b)},_doFinalize:function(){var a=this.cfg.padding;if(this._xformMode==this._ENC_XFORM_MODE){a.pad(this._data,this.blockSize);var b=this._process(!0)}else b=this._process(!0),a.unpad(b);return b},blockSize:4});var n=d.CipherParams=l.extend({init:function(a){this.mixIn(a)},toString:function(a){return(a||this.formatter).stringify(this)}}),b=(p.format={}).OpenSSL={stringify:function(a){var b=a.ciphertext;a=a.salt;return(a?s.create([1398893684,
|
||||
1701076831]).concat(a).concat(b):b).toString(r)},parse:function(a){a=r.parse(a);var b=a.words;if(1398893684==b[0]&&1701076831==b[1]){var c=s.create(b.slice(2,4));b.splice(0,4);a.sigBytes-=16}return n.create({ciphertext:a,salt:c})}},a=d.SerializableCipher=l.extend({cfg:l.extend({format:b}),encrypt:function(a,b,c,d){d=this.cfg.extend(d);var l=a.createEncryptor(c,d);b=l.finalize(b);l=l.cfg;return n.create({ciphertext:b,key:c,iv:l.iv,algorithm:a,mode:l.mode,padding:l.padding,blockSize:a.blockSize,formatter:d.format})},
|
||||
decrypt:function(a,b,c,d){d=this.cfg.extend(d);b=this._parse(b,d.format);return a.createDecryptor(c,d).finalize(b.ciphertext)},_parse:function(a,b){return"string"==typeof a?b.parse(a,this):a}}),p=(p.kdf={}).OpenSSL={execute:function(a,b,c,d){d||(d=s.random(8));a=w.create({keySize:b+c}).compute(a,d);c=s.create(a.words.slice(b),4*c);a.sigBytes=4*b;return n.create({key:a,iv:c,salt:d})}},c=d.PasswordBasedCipher=a.extend({cfg:a.cfg.extend({kdf:p}),encrypt:function(b,c,d,l){l=this.cfg.extend(l);d=l.kdf.execute(d,
|
||||
b.keySize,b.ivSize);l.iv=d.iv;b=a.encrypt.call(this,b,c,d.key,l);b.mixIn(d);return b},decrypt:function(b,c,d,l){l=this.cfg.extend(l);c=this._parse(c,l.format);d=l.kdf.execute(d,b.keySize,b.ivSize,c.salt);l.iv=d.iv;return a.decrypt.call(this,b,c,d.key,l)}})}();
|
||||
(function(){for(var u=CryptoJS,p=u.lib.BlockCipher,d=u.algo,l=[],s=[],t=[],r=[],w=[],v=[],b=[],x=[],q=[],n=[],a=[],c=0;256>c;c++)a[c]=128>c?c<<1:c<<1^283;for(var e=0,j=0,c=0;256>c;c++){var k=j^j<<1^j<<2^j<<3^j<<4,k=k>>>8^k&255^99;l[e]=k;s[k]=e;var z=a[e],F=a[z],G=a[F],y=257*a[k]^16843008*k;t[e]=y<<24|y>>>8;r[e]=y<<16|y>>>16;w[e]=y<<8|y>>>24;v[e]=y;y=16843009*G^65537*F^257*z^16843008*e;b[k]=y<<24|y>>>8;x[k]=y<<16|y>>>16;q[k]=y<<8|y>>>24;n[k]=y;e?(e=z^a[a[a[G^z]]],j^=a[a[j]]):e=j=1}var H=[0,1,2,4,8,
|
||||
16,32,64,128,27,54],d=d.AES=p.extend({_doReset:function(){for(var a=this._key,c=a.words,d=a.sigBytes/4,a=4*((this._nRounds=d+6)+1),e=this._keySchedule=[],j=0;j<a;j++)if(j<d)e[j]=c[j];else{var k=e[j-1];j%d?6<d&&4==j%d&&(k=l[k>>>24]<<24|l[k>>>16&255]<<16|l[k>>>8&255]<<8|l[k&255]):(k=k<<8|k>>>24,k=l[k>>>24]<<24|l[k>>>16&255]<<16|l[k>>>8&255]<<8|l[k&255],k^=H[j/d|0]<<24);e[j]=e[j-d]^k}c=this._invKeySchedule=[];for(d=0;d<a;d++)j=a-d,k=d%4?e[j]:e[j-4],c[d]=4>d||4>=j?k:b[l[k>>>24]]^x[l[k>>>16&255]]^q[l[k>>>
|
||||
8&255]]^n[l[k&255]]},encryptBlock:function(a,b){this._doCryptBlock(a,b,this._keySchedule,t,r,w,v,l)},decryptBlock:function(a,c){var d=a[c+1];a[c+1]=a[c+3];a[c+3]=d;this._doCryptBlock(a,c,this._invKeySchedule,b,x,q,n,s);d=a[c+1];a[c+1]=a[c+3];a[c+3]=d},_doCryptBlock:function(a,b,c,d,e,j,l,f){for(var m=this._nRounds,g=a[b]^c[0],h=a[b+1]^c[1],k=a[b+2]^c[2],n=a[b+3]^c[3],p=4,r=1;r<m;r++)var q=d[g>>>24]^e[h>>>16&255]^j[k>>>8&255]^l[n&255]^c[p++],s=d[h>>>24]^e[k>>>16&255]^j[n>>>8&255]^l[g&255]^c[p++],t=
|
||||
d[k>>>24]^e[n>>>16&255]^j[g>>>8&255]^l[h&255]^c[p++],n=d[n>>>24]^e[g>>>16&255]^j[h>>>8&255]^l[k&255]^c[p++],g=q,h=s,k=t;q=(f[g>>>24]<<24|f[h>>>16&255]<<16|f[k>>>8&255]<<8|f[n&255])^c[p++];s=(f[h>>>24]<<24|f[k>>>16&255]<<16|f[n>>>8&255]<<8|f[g&255])^c[p++];t=(f[k>>>24]<<24|f[n>>>16&255]<<16|f[g>>>8&255]<<8|f[h&255])^c[p++];n=(f[n>>>24]<<24|f[g>>>16&255]<<16|f[h>>>8&255]<<8|f[k&255])^c[p++];a[b]=q;a[b+1]=s;a[b+2]=t;a[b+3]=n},keySize:8});u.AES=p._createHelper(d)})();
|
After Width: | Height: | Size: 434 KiB |
|
@ -0,0 +1,66 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<!-- Copyright (c) 2017 Kevin Froman MIT (expat) license -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||
<meta name='description' content="Perform Whitespace steganography with encryption and zero width characters">
|
||||
<meta name='author' content='Kevin Froman'>
|
||||
<title>Snow10</title>
|
||||
<link rel="stylesheet" href="./bootstrap.min.css">
|
||||
<link rel="stylesheet" href="./bootstrap-theme.min.css">
|
||||
<link rel="stylesheet" href="./font-awesome.min.css">
|
||||
<script src="./jquery.min.js"></script>
|
||||
<script src="./bootstrap.min.js"></script>
|
||||
<script src="./clipboard.min.js"></script>
|
||||
<script src='./aes.min.js'></script>
|
||||
<link rel='stylesheet' href='./theme.min.css'>
|
||||
<style>p{ font-family: serif; }</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class='container'>
|
||||
|
||||
<div class='page-header'>
|
||||
<h1 class='center'>Snow10 ☃</h1>
|
||||
</div>
|
||||
|
||||
<p class='center'><a href='./index.html' class='btn btn-primary'>Go Back</a></p>
|
||||
|
||||
<h1>About</h1>
|
||||
<p>Snow10 is a free and open-source web and Android app for converting messages into invisible whitespace characters and back again.</p>
|
||||
<br>
|
||||
<img src='./snow.jpg' alt='snow image'>
|
||||
<br><br>
|
||||
<p><a href='https://github.com/beardog108/snow10/'>It is available on Github</a>.</p>
|
||||
<h1>Encoding Basics</h1>
|
||||
<p>Snow10 messages are meant to be embedded elsewhere, specifically within or by standard blocks of text.</p>
|
||||
<p>Messages with the 'zero width characters' setting work in most places that accept unicode input.</p>
|
||||
<p>Simply enter the message you want to hide <b>(waring: larger messages are more noticeable, and really massive messages may be dangerous/not work)</b></p>
|
||||
<p>You can uncheck 'use zero width characters' but this is more noticeable in some cases and is more likely to be stripped out.</p>
|
||||
<p>Then, enter a decent password in both passwords fields to encrypt your message (or disable encryption, but note that doing so will let anyone read your message.)</p>
|
||||
<p>Press 'encode' and wait for the output window to show, then, press 'copy to clipboard'.</p>
|
||||
<p>You can now paste your message inside Twitter DMs, social media posts, word documents, or elsewhere.</p>
|
||||
|
||||
<h2>Decoding Basics</h2>
|
||||
|
||||
<p>To retrieve a Snow10 message, copy paste it into the text field.</p>
|
||||
<p>It is important to get the full message, & if not using 'zero width characters', then remove any non-message text. <b>This can be difficult, but failing to do so many result in an incomplete or corrupted message.</b></p>
|
||||
<p>If the message is encrypted, enter the password (you only need to enter it into the first field to decode).</p>
|
||||
<p>If the message is not encrypted, uncheck 'use encryption'</p>
|
||||
<p>Then, press decode.</p>
|
||||
<p>If all went right, then you should see the decoded message.</p>
|
||||
|
||||
<h2>Example</h2>
|
||||
|
||||
<p>Here is an example of Snow10's use.</p>
|
||||
|
||||
<input type='text' readonly value='Put this into Snow10' onclick='this.select();'>
|
||||
<br><br>
|
||||
<p class='center'><a href='./index.html' class='btn btn-primary'>Go Back</a></p>
|
||||
|
||||
</div>
|
||||
<footer class='center'>made with <i class='fa fa-heart'></i> by <a href='https://chaoswebs.net/'>Beardog</a></footer>
|
||||
<script src='./main.js'></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,74 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<!-- Copyright (c) 2017 Kevin Froman MIT (expat) license -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||
<meta name='description' content="Perform Whitespace steganography with encryption and zero width characters">
|
||||
<meta name='author' content='Kevin Froman'>
|
||||
<title>Snow10</title>
|
||||
<link rel="stylesheet" href="./bootstrap.min.css">
|
||||
<link rel="stylesheet" href="./bootstrap-theme.min.css">
|
||||
<link rel="stylesheet" href="./font-awesome.min.css">
|
||||
<script src="./jquery.min.js"></script>
|
||||
<script src="./bootstrap.min.js"></script>
|
||||
<script src="./clipboard.min.js"></script>
|
||||
<script src="./jquery.bootstrap-growl.min.js"></script>
|
||||
<script src='./aes.min.js'></script>
|
||||
<link rel='stylesheet' href='./theme.min.css'>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="modal" id="outputModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title center" id="myModalLabel">Your Text Is Ready!</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<br>
|
||||
<pre id='output'></pre>
|
||||
<div class='center'><button class="btn btn-success" data-clipboard-action="copy" data-clipboard-target="#output">Copy to Clipboard</button></div>
|
||||
<div id='copyFeedback' class='center'></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal" id='modalClose'>Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class='container'>
|
||||
|
||||
<div class='page-header'>
|
||||
<h1 class='center'>Snow10 ☃</h1>
|
||||
</div>
|
||||
<p class='center'><a href='help.html'>Help! I'm confused!</a></p>
|
||||
<div id='dataArea'>
|
||||
<textarea id='text' placeholder=''></textarea>
|
||||
</div>
|
||||
<div class='center'><button class='btn btn-sm btn-default dataItem' id='clearInputButton'>Clear Input <i class='fa fa-cross'></i></button></div>
|
||||
<br><br>
|
||||
<div class='center'>
|
||||
<label>Use Zero-Width Characters <input type='checkbox' id='useZeroWidthCharacters' checked></label>
|
||||
<br><br>
|
||||
<label>Use Encryption <input type='checkbox' id='useEncrypt'></label>
|
||||
<br><br>
|
||||
<span id='encryptArea'>
|
||||
<input type='password' id='password' placeholder='Encryption password' class='dataItem'>
|
||||
<br>
|
||||
<input type='password' id='confirmPass' placeholder='Confirm password' class='dataItem'>
|
||||
<br>
|
||||
</span>
|
||||
<div class="btn-group" role="group" aria-label="...">
|
||||
<button type="button" class="btn btn-primary" id="encode">Encode <i class='fa fa-lock'></i></button>
|
||||
<button type="button" class="btn btn-primary" id="decode">Decode <i class='fa fa-unlock'></i></button>
|
||||
</div>
|
||||
<br>
|
||||
</div>
|
||||
</div>
|
||||
<footer class='center'>made with <i class='fa fa-heart'></i> by <a href='https://chaoswebs.net/'>Beardog</a></footer>
|
||||
<script src='./main.js'></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1 @@
|
|||
(function(){var c;c=jQuery;c.bootstrapGrowl=function(f,a){var b,e,d;a=c.extend({},c.bootstrapGrowl.default_options,a);b=c("<div>");b.attr("class","bootstrap-growl alert");a.type&&b.addClass("alert-"+a.type);a.allow_dismiss&&(b.addClass("alert-dismissible"),b.append('<button class="close" data-dismiss="alert" type="button"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>'));b.append(f);a.top_offset&&(a.offset={from:"top",amount:a.top_offset});d=a.offset.amount;c(".bootstrap-growl").each(function(){return d= Math.max(d,parseInt(c(this).css(a.offset.from))+c(this).outerHeight()+a.stackup_spacing)});e={position:"body"===a.ele?"fixed":"absolute",margin:0,"z-index":"9999",display:"none"};e[a.offset.from]=d+"px";b.css(e);"auto"!==a.width&&b.css("width",a.width+"px");c(a.ele).append(b);switch(a.align){case "center":b.css({left:"50%","margin-left":"-"+b.outerWidth()/2+"px"});break;case "left":b.css("left","20px");break;default:b.css("right","20px")}b.fadeIn();0<a.delay&&b.delay(a.delay).fadeOut(function(){return c(this).alert("close")}); return b};c.bootstrapGrowl.default_options={ele:"body",type:"info",offset:{from:"top",amount:20},align:"right",width:250,delay:4E3,allow_dismiss:!0,stackup_spacing:10}}).call(this);
|
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
Copyright (c) 2017 Kevin Froman MIT (expat) license
|
||||
*/
|
||||
var clipboard = new Clipboard('.btn');
|
||||
|
||||
var zero = '';
|
||||
var one = '';
|
||||
|
||||
var z_zero = '';
|
||||
var z_one = '';
|
||||
|
||||
var w_zero = ' ';
|
||||
var w_one = '\t';
|
||||
|
||||
|
||||
function showError(msg){
|
||||
$.bootstrapGrowl(msg, {type: 'danger'})
|
||||
}
|
||||
|
||||
function escapeRegExp(str) {
|
||||
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
|
||||
}
|
||||
|
||||
function replaceAll(str, find, replace) {
|
||||
return str.replace(new RegExp(escapeRegExp(find), 'g'), replace);
|
||||
}
|
||||
|
||||
clipboard.on('success', function(e) {
|
||||
$('#copyFeedback').css('display', 'inherit');
|
||||
$('#copyFeedback').css('color', 'green');
|
||||
$('#copyFeedback').html('Copied!');
|
||||
e.clearSelection();
|
||||
});
|
||||
|
||||
clipboard.on('error', function(e) {
|
||||
$('#copyFeedback').css('display', 'inherit');
|
||||
$('#copyFeedback').css('color', 'red');
|
||||
$('#copyFeedback').html('Your browser doesn\'t seem to support automatic copying. Get a better one.');
|
||||
e.clearSelection();
|
||||
});
|
||||
|
||||
if ($('#useEncrypt').is(':checked') == false)
|
||||
{
|
||||
$('#encryptArea').css('display', 'none');
|
||||
}
|
||||
|
||||
$('#modalClose').click(function(){
|
||||
$('#copyFeedback').css('display', 'none');
|
||||
});
|
||||
|
||||
|
||||
$("#output").on("click", function () {
|
||||
$(this).select();
|
||||
});
|
||||
|
||||
$('#useZeroWidthCharacters').click(function(){
|
||||
|
||||
if (zero == w_zero)
|
||||
{
|
||||
zero = z_zero;
|
||||
one = z_one;
|
||||
}
|
||||
else
|
||||
{
|
||||
zero = w_zero;
|
||||
one = z_one;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
/* based on stackoverflow.com/questions/14430633/how-to-convert-text-to-binary-code-in-javascript */
|
||||
function binToText(str) {
|
||||
var str = replaceAll(replaceAll(str, one, "1"), zero, "0");
|
||||
if(str.match(/[10]{8}/g)){
|
||||
var wordFromBinary = str.match(/([10]{8}|\s+)/g).map(function(fromBinary){
|
||||
return String.fromCharCode(parseInt(fromBinary, 2) );
|
||||
}).join('');
|
||||
return wordFromBinary;
|
||||
}
|
||||
}
|
||||
|
||||
/* based on stackoverflow.com/questions/21354235/converting-binary-to-text-using-javascript */
|
||||
function textToBin(text) {
|
||||
var output = '';
|
||||
var length = text.length,
|
||||
output = [];
|
||||
for (var i = 0;i < length; i++) {
|
||||
var bin = text[i].charCodeAt().toString(2);
|
||||
output.push(Array(8-bin.length+1).join("0") + bin);
|
||||
}
|
||||
return output.join('');
|
||||
}
|
||||
|
||||
$('#useEncrypt').click(function(){
|
||||
if (! this.checked)
|
||||
{
|
||||
$('#encryptArea').css('display', 'none');
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#encryptArea').css('display', 'inherit');
|
||||
}
|
||||
})
|
||||
|
||||
function verifyPass(mode)
|
||||
{
|
||||
if ($('#password').val() == '')
|
||||
{
|
||||
showError('You must provide a password.');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mode == 'encrypt')
|
||||
{
|
||||
if ($('#password').val() != $('#confirmPass').val())
|
||||
{
|
||||
showError('Passwords must match.');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
$('#encode').click(function(){
|
||||
go('encode');
|
||||
});
|
||||
$('#decode').click(function(){
|
||||
go('decode');
|
||||
});
|
||||
|
||||
function go(mode) {
|
||||
var output = '';
|
||||
|
||||
var input = $('#text').val();
|
||||
|
||||
if (input == '') { return false; }
|
||||
|
||||
|
||||
// If we're encoding:
|
||||
if (mode == 'encode')
|
||||
{
|
||||
// If we should use encryption, encrypt first:
|
||||
if ($('#useEncrypt').is(':checked'))
|
||||
{
|
||||
// verify password first
|
||||
if (verifyPass('encrypt'))
|
||||
{
|
||||
input = CryptoJS.AES.encrypt(input, $('#password').val()).toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// convert result to binary
|
||||
output = textToBin(encodeURIComponent(input));
|
||||
$('#output').text(replaceAll(replaceAll(output.toString(), "1", one), "0", zero));
|
||||
}
|
||||
else
|
||||
{
|
||||
var sanitized = "";
|
||||
var split = input.split("");
|
||||
for (var i = 0; i < split.length; i++)
|
||||
if(split[i] == one || split[i] == zero)
|
||||
sanitized = sanitized + split[i]
|
||||
var output = decodeURIComponent(binToText(sanitized));
|
||||
if ($('#useEncrypt').is(':checked'))
|
||||
{
|
||||
if (verifyPass('decrypt'))
|
||||
{
|
||||
output = CryptoJS.AES.decrypt(output, $('#password').val()).toString(CryptoJS.enc.Utf8);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$('#output').text(output.toString());
|
||||
}
|
||||
$('#outputModal').modal();
|
||||
}
|
||||
|
||||
$('#clearInputButton').click(function(){
|
||||
$('#text').val('');
|
||||
});
|
After Width: | Height: | Size: 22 KiB |
|
@ -0,0 +1,57 @@
|
|||
body
|
||||
{
|
||||
background-color: #d8d8d8;
|
||||
color: black;
|
||||
}
|
||||
.center
|
||||
{
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#dataArea
|
||||
{
|
||||
margin-left: 3em;
|
||||
margin-right: 3em;
|
||||
}
|
||||
|
||||
#text
|
||||
{
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
min-height: 300px;
|
||||
}
|
||||
|
||||
#one
|
||||
{
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.dataItem
|
||||
{
|
||||
margin: 1em;
|
||||
}
|
||||
|
||||
footer
|
||||
{
|
||||
margin-top: 1em;
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
#copyFeedback
|
||||
{
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
#outputDecode, #copyFeedback{
|
||||
display: none;
|
||||
}
|
||||
|
||||
#outputDecode{
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
p, h1, h2 {
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
body{background-color:#d8d8d8;color:black}.center{text-align:center}#dataArea{margin-left:3em;margin-right:3em}#text{width:100%;max-width:100%;min-height:300px}#one{margin-bottom:1em}.dataItem{margin:1em}footer{margin-top:1em;margin-bottom:2em}#copyFeedback{margin-top:1em;margin-bottom:1em}#outputDecode,#copyFeedback{display:none}#outputDecode{overflow:scroll}p,h1,h2{user-select:none;-webkit-user-select:none}
|
|
@ -0,0 +1,58 @@
|
|||
package net.chaoswebs.snow10;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.os.Bundle;
|
||||
import android.view.KeyEvent;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
// Copyright (c) 2017 Kevin Froman MIT (expat) license
|
||||
|
||||
private WebView view;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
view = new WebView(this);
|
||||
view.setWebViewClient(new WebViewClient(){
|
||||
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
||||
if (url != null && url.startsWith("http://") || url.startsWith("https://")) {
|
||||
view.getContext().startActivity(
|
||||
new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
view.getSettings().setJavaScriptEnabled(true);
|
||||
view.loadUrl("file:///android_asset/index.html");
|
||||
setContentView(view);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
if ((keyCode == KeyEvent.KEYCODE_BACK) && view.canGoBack()) {
|
||||
//if Back key pressed and webview can navigate to previous page
|
||||
view.goBack();
|
||||
// go back to previous page
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
finish();
|
||||
// finish the activity
|
||||
}
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--Copyright (c) 2017 Kevin Froman MIT (expat) license-->
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/activity_main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin" tools:context="net.chaoswebs.snow10.MainActivity">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="If you can read this, you probably don't have webview installed" />
|
||||
</RelativeLayout>
|
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 6.0 KiB |
After Width: | Height: | Size: 8.7 KiB |
After Width: | Height: | Size: 9.8 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 14 KiB |
|
@ -0,0 +1,6 @@
|
|||
<resources>
|
||||
<!-- Example customization of dimensions originally defined in res/values/dimens.xml
|
||||
(such as screen margins) for screens with more than 820dp of available width. This
|
||||
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
|
||||
<dimen name="activity_horizontal_margin">64dp</dimen>
|
||||
</resources>
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#3F51B5</color>
|
||||
<color name="colorPrimaryDark">#303F9F</color>
|
||||
<color name="colorAccent">#FF4081</color>
|
||||
</resources>
|
|
@ -0,0 +1,5 @@
|
|||
<resources>
|
||||
<!-- Default screen margins, per the Android Design guidelines. -->
|
||||
<dimen name="activity_horizontal_margin">16dp</dimen>
|
||||
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||
</resources>
|
|
@ -0,0 +1,3 @@
|
|||
<resources>
|
||||
<string name="app_name">Snow10</string>
|
||||
</resources>
|
|
@ -0,0 +1,11 @@
|
|||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
</style>
|
||||
|
||||
</resources>
|