|
|
(38 intermediate revisions by the same user not shown) |
Line 1: |
Line 1: |
− | <!DOCTYPE html>
| + | #REDIRECT [[Team:Groningen/Encoding]] |
− | <html>
| + | |
− | <head>
| + | |
− | <meta http-equiv="content-type" content="text/html; charset=utf-8" />
| + | |
− | <title>SpyGEM coding</title>
| + | |
− | <style>
| + | |
− | body{
| + | |
− | font-family: sans-serif;
| + | |
− | font-size: 13pt;
| + | |
− | line-height: 1.5em;
| + | |
− | padding: 0.5em;
| + | |
− | margin: 0;
| + | |
− | }
| + | |
− | body,textarea,a{
| + | |
− | background-color: #222;
| + | |
− | color: #EEE;
| + | |
− | }
| + | |
− | textarea,code{
| + | |
− | font-family: monospace;
| + | |
− | font-size: 12pt;
| + | |
− | line-height: 1.5em;
| + | |
− | }
| + | |
− | textarea{
| + | |
− | border: 1px solid #444;
| + | |
− | width: 99%;
| + | |
− | }
| + | |
− | h1{
| + | |
− | font-size: 1.2em;
| + | |
− | }
| + | |
− |
| + | |
− | #container{
| + | |
− | overflow: auto;
| + | |
− | width: 100%;
| + | |
− | margin: 0;
| + | |
− | padding: 0;
| + | |
− | }
| + | |
− | #sec-left{
| + | |
− | padding: 5px;
| + | |
− | width: 58.5%;
| + | |
− | float: left;
| + | |
− | }
| + | |
− | #sec-right{
| + | |
− | padding: 5px;
| + | |
− | width: 38.5%;
| + | |
− | float: right;
| + | |
− | }
| + | |
− |
| + | |
− | #err{
| + | |
− | color: #FF3333;
| + | |
− | }
| + | |
− |
| + | |
− | .input{
| + | |
− | border: 1px solid #EEE;
| + | |
− | }
| + | |
− | .strike{
| + | |
− | text-decoration: line-through;
| + | |
− | }
| + | |
− | .vr{
| + | |
− | border-left: 1px solid #EEE;
| + | |
− | width: 0;
| + | |
− | padding: 0;
| + | |
− | margin: 0;
| + | |
− | }
| + | |
− | .clear{
| + | |
− | clear: both;
| + | |
− | }
| + | |
− | </style>
| + | |
− | </head>
| + | |
− | <body>
| + | |
− | <div id="container">
| + | |
− | <h1>SpyGEM coding & crypting</h1>
| + | |
− | <hr class="clear" />
| + | |
− | <div id="sec-left">
| + | |
− | <p><div><!--Sub-coding:
| + | |
− | <span>
| + | |
− | <input class="subcode" type="radio" id="code64" name="subcode" value="64" />
| + | |
− | <label for="code64">Six-four</label>
| + | |
− | </span>
| + | |
− | <span>
| + | |
− | <input class="subcode" type="radio" id="code8" name="subcode" value="8bit" checked />
| + | |
− | <label for="code8">8-bit</label>
| + | |
− | </span>
| + | |
− | <span>
| + | |
− | <input class="subcode" type="radio" id="codex4" name="subcode" value="ex4" />
| + | |
− | <label for="codex4">Ex-four</label>
| + | |
− | </span>
| + | |
− | <span class="vr">​</span>-->
| + | |
− | <span>
| + | |
− | <input type="checkbox" id="crypt" />
| + | |
− | <label for="crypt">Encrypt</label>
| + | |
− | </span>
| + | |
− | <span class="vr">​</span>
| + | |
− | <span>
| + | |
− | <input class="dir" type="radio" id="doEnc" name="dir" value="enc" checked />
| + | |
− | <label for="doEnc">Encode</label>
| + | |
− | </span>
| + | |
− | <span>
| + | |
− | <input class="dir" type="radio" id="doDec" name="dir" value="dec" />
| + | |
− | <label for="doDec">Decode</label>
| + | |
− | </span>
| + | |
− | </div></p>
| + | |
− | <p><div>Message</div><div><textarea class="input" rows="5" id="msg">Hello world.</textarea></div></p>
| + | |
− | <p><div>Key</div><div><textarea class="input" rows="5" id="key"></textarea></div></p>
| + | |
− | <p><div>Formatted</div><textarea rows="5" id="fmt"></textarea></p>
| + | |
− | <p><div>Encoded</div><div><textarea class="input" rows="5" id="enc"></textarea></div></p>
| + | |
− | <p><div>Total length: <span id="len"></span> bases</div></p>
| + | |
− | <p><div id="err"></div></p>
| + | |
− | </div>
| + | |
− | <div id="sec-right">
| + | |
− | <p>This page demonstrates the encoding and decoding of text messages
| + | |
− | into DNA, optionally with AES-256 encryption.</p>
| + | |
− | <p>Enter a message into the Message field to have it encoded, or
| + | |
− | enter an encoded message into the Encoded field to have it decoded.
| + | |
− | The Key field is used for encryption & decryption and the
| + | |
− | Formatted field shows more details about the message block.</p>
| + | |
− | <!--<span class="strike"><p>The encoding uses 6 bits, or 3 bases, per character,
| + | |
− | so the permitted characters are:</p>
| + | |
− | <p><ul>
| + | |
− | <li>digits: <code>'0' - '9'</code>,</li>
| + | |
− | <li>lower-case letters: <code>'a' - 'z'</code>,</li>
| + | |
− | <li>upper-case letters: <code>'A' - 'Z'</code>,</li>
| + | |
− | <li>space: <code>' '</code>, and</li>
| + | |
− | <li>full-stop: <code>'.'</code>.</li>
| + | |
− | </ul></p></span>-->
| + | |
− | <!--<p>Different encodings for the message are possible. Both
| + | |
− | 'Six-four' and 'Ex-four' use 6 bits (3 bases) per character,
| + | |
− | but are limited in the characters they allow. 'Six-four' allows
| + | |
− | only upper- and lower-case letters, digits, space and full-stop.
| + | |
− | 'Ex-four' is somewhat experimental and allows more characters
| + | |
− | (all of ASCII and a few more), but needs 12 bits for some characters,
| + | |
− | most notably for upper-case.</p>-->
| + | |
− | <p>To counter restriction enzymes a sequence of 'A'-bases is
| + | |
− | inserted whereever the sequence for a restriction-enzyme occurs.
| + | |
− | When decoding the message these sequences are removed. The length
| + | |
− | of the substitution sequence is the shortest sequence of
| + | |
− | 'A' that does not occur in the encoded message.</p>
| + | |
− | <p>The encoding requires 4 bases per character.</p>
| + | |
− | <p>The fully encoded message block is formatted as follows:</p>
| + | |
− | <p><ol>
| + | |
− | <li>The letters <code>'Spy'</code>: 3 × 4 bases.</li>
| + | |
− | <li>Padding: 4 'A' bases.</li>
| + | |
− | <li>The length of the restriction-substitutes: 8-bit number (4 bases).</li>
| + | |
− | <li>The length of the encoded message: 16-bit number (8 bases).</li>
| + | |
− | <li>The checksum of the encoded message: 16-bit number (8 bases).</li>
| + | |
− | <li>The message: 4 bases per character.</li>
| + | |
− | <li>The letters <code>'GEM'</code>: 3 × 4 bases.</li>
| + | |
− | </ol></p>
| + | |
− | <p>The total overhead is 48 bases and the maximum message
| + | |
− | length is 65535 characters.</p>
| + | |
− | <p>Encryption has an additional 8 characters (48 bases) overhead,
| + | |
− | regardless of key or message length.</p>
| + | |
− | </div>
| + | |
− | </div>
| + | |
− | <div class="clear"></div>
| + | |
− | <div>
| + | |
− | <p>Credits:</p>
| + | |
− | <ul>
| + | |
− | <li><a href="http://www.movable-type.co.uk/scripts/aes.html">Chris Veness: Javascript implementation of AES</a></li>
| + | |
− | <li><a href="https://gist.github.com/chitchcock/5112270">'chitchcock': Javascript implementation of CRC16-CCITT</a></li>
| + | |
− | </ul>
| + | |
− | </div>
| + | |
− |
| + | |
− | <script src="/Template:Groningen/crc_js?action=raw&ctype=text/javascript"></script>
| + | |
− | <script src="/Template:Groningen/dna_js?action=raw&ctype=text/javascript"></script>
| + | |
− | <script src="/Template:Groningen/eightbit_js?action=raw&ctype=text/javascript"></script>
| + | |
− | <script src="/Template:Groningen/sixfour_js?action=raw&ctype=text/javascript"></script>
| + | |
− | <script src="/Template:Groningen/restrict_js?action=raw&ctype=text/javascript"></script>
| + | |
− | <script src="/Template:Groningen/message_js?action=raw&ctype=text/javascript"></script>
| + | |
− | <script src="/Template:Groningen/exfour_js?action=raw&ctype=text/javascript"></script>
| + | |
− | <script src="/Template:Groningen/aes_js?action=raw&ctype=text/javascript"></script>
| + | |
− | <script src="/Template:Groningen/aes-ctr_js?action=raw&ctype=text/javascript"></script>
| + | |
− | <script src="/Template:Groningen/splitter_js?action=raw&ctype=text/javascript"></script>
| + | |
− | <script>
| + | |
− | if(typeof Array.from !== 'function'){
| + | |
− | Array.from = function(src){
| + | |
− | return Array.prototype.slice.call(src);
| + | |
− | };
| + | |
− | }
| + | |
− | | + | |
− | var elMsg = document.getElementById('msg'),
| + | |
− | elKey = document.getElementById('key'),
| + | |
− | elFmt = document.getElementById('fmt'),
| + | |
− | elEnc = document.getElementById('enc'),
| + | |
− | elErr = document.getElementById('err'),
| + | |
− | elCrypt = document.getElementById('crypt'),
| + | |
− | elCode8 = document.getElementById('code8'),
| + | |
− | elDoEnc = document.getElementById('doEnc'),
| + | |
− | elDoDec = document.getElementById('doDec'),
| + | |
− | elDirs = [elDoEnc, elDoDec],
| + | |
− | elSubs = Array.from(document.getElementsByClassName('subcode')),
| + | |
− | elLen = document.getElementById('len');
| + | |
− |
| + | |
− | var subCoding = EightBit, doCrypt = false, lastEdit = elMsg, cryptBits = 256;
| + | |
− |
| + | |
− | function showEncHdr(hdr, data){
| + | |
− | elFmt.value = 'Start: Spy = '+hdr.dnaStart+', End: GEM = '+hdr.dnaEnd+
| + | |
− | '\nSubst: '+hdr.subst+' = '+hdr.dnaSubst+
| + | |
− | '\nLength: '+hdr.len+' = '+hdr.dnaLen+
| + | |
− | '\nCRC16: '+hdr.crc+' = '+hdr.dnaCrc+'\nData: '+data;
| + | |
− | }
| + | |
− |
| + | |
− | function showDecHdr(hdr){
| + | |
− | elFmt.value = 'Start: '+hdr.dnaStart+' = Spy, End: '+hdr.dnaEnd+' = GEM'+
| + | |
− | '\nSubst: '+hdr.dnaSubst+' = '+hdr.subst+
| + | |
− | '\nLength: '+hdr.dnaLen+' = '+hdr.len+
| + | |
− | '\nCRC16: '+hdr.dnaCrc+' = '+hdr.crc+'\nData: '+hdr.data;
| + | |
− | }
| + | |
− |
| + | |
− | function clearEls(){
| + | |
− | elErr.innerHTML = '';
| + | |
− | //elMsg.value = '';
| + | |
− | elFmt.value = '';
| + | |
− | //elEnc.value = '';
| + | |
− | }
| + | |
− |
| + | |
− | function updateEnc(){
| + | |
− | var msg = elMsg.value, data, key;
| + | |
− | elEnc.value = '';
| + | |
− | clearEls();
| + | |
− | updateDir(elMsg);
| + | |
− |
| + | |
− | if(doCrypt){
| + | |
− | key = elKey.value;
| + | |
− | msg = Aes.Ctr.encrypt(msg, key, cryptBits);
| + | |
− | }
| + | |
− | data = subCoding.encodeStr(msg);
| + | |
− |
| + | |
− | if(data === null){
| + | |
− | elErr.innerHTML = 'Illegal character in input message';
| + | |
− | return;
| + | |
− | }
| + | |
− |
| + | |
− | var hdr, dna;
| + | |
− |
| + | |
− | try{
| + | |
− | hdr = Message.packDNA(data, 1);
| + | |
− | dna = hdr.msg;
| + | |
− | }catch(e){
| + | |
− | elErr.innerHTML = e.message;
| + | |
− | console.error(e);
| + | |
− | return;
| + | |
− | }
| + | |
− |
| + | |
− | showEncHdr(hdr, data);
| + | |
− | elEnc.value = dna;
| + | |
− | elLen.innerHTML = dna.length;
| + | |
− | }
| + | |
− |
| + | |
− | function updateDec(){
| + | |
− | var dna = elEnc.value, hdr, msg, key;
| + | |
− | elMsg.value = '';
| + | |
− | clearEls();
| + | |
− | updateDir(elEnc);
| + | |
− |
| + | |
− | try{
| + | |
− | hdr = Message.unpackDNA(dna, 1);
| + | |
− | msg = subCoding.decodeStr(hdr.data);
| + | |
− | }catch(e){
| + | |
− | elErr.innerHTML = e.message;
| + | |
− | console.error(e);
| + | |
− | return;
| + | |
− | }
| + | |
− |
| + | |
− | if(msg === null){
| + | |
− | elErr.innerHTML = 'Message data cannot be decoded';
| + | |
− | return;
| + | |
− | }
| + | |
− |
| + | |
− | if(doCrypt){
| + | |
− | key = elKey.value;
| + | |
− | msg = Aes.Ctr.decrypt(msg, key, cryptBits);
| + | |
− | }
| + | |
− |
| + | |
− | showDecHdr(hdr);
| + | |
− | elMsg.value = msg;
| + | |
− | elLen.innerHTML = dna.length;
| + | |
− | }
| + | |
− |
| + | |
− | function updateLast(){
| + | |
− | if(lastEdit === elMsg){
| + | |
− | updateEnc();
| + | |
− | }else{
| + | |
− | updateDec();
| + | |
− | }
| + | |
− | }
| + | |
− |
| + | |
− | function updateSubCode(){
| + | |
− | if(!this.checked){
| + | |
− | return;
| + | |
− | }
| + | |
− |
| + | |
− | switch(this.value){
| + | |
− | case '64': subCoding = SixFour; break;
| + | |
− | case '8bit': subCoding = EightBit; break;
| + | |
− | case 'ex4': subCoding = ExFour; break;
| + | |
− | }
| + | |
− |
| + | |
− | updateLast();
| + | |
− | }
| + | |
− |
| + | |
− | function updateCrypt(){
| + | |
− | if(this === elKey) if(this.value.length > 0){
| + | |
− | elCrypt.checked = true;
| + | |
− | }
| + | |
− |
| + | |
− | if(elCrypt.checked){
| + | |
− | doCrypt = true;
| + | |
− | subCoding = EightBit;
| + | |
− | }else{
| + | |
− | doCrypt = false;
| + | |
− | }
| + | |
− |
| + | |
− | updateLast();
| + | |
− | }
| + | |
− |
| + | |
− | function updateDir(last){
| + | |
− | if(last){
| + | |
− | lastEdit = last;
| + | |
− |
| + | |
− | elDoEnc.checked = last === elMsg;
| + | |
− | elDoDec.checked = last === elEnc;
| + | |
− |
| + | |
− | return;
| + | |
− | }
| + | |
− | }
| + | |
− |
| + | |
− | elMsg.onchange = updateEnc;
| + | |
− | elMsg.onkeyup = updateEnc;
| + | |
− |
| + | |
− | elEnc.onchange = updateDec;
| + | |
− | elEnc.onkeyup = updateDec;
| + | |
− |
| + | |
− | elKey.onchange = updateCrypt.bind(elKey);
| + | |
− | elKey.onkeyup = updateCrypt.bind(elKey);
| + | |
− |
| + | |
− | elSubs.forEach(function(el){
| + | |
− | el.onchange = updateSubCode.bind(el);
| + | |
− | });
| + | |
− | elDirs.forEach(function(el){
| + | |
− | el.onchange = function(){
| + | |
− | if(!this.checked){
| + | |
− | return;
| + | |
− | }
| + | |
− |
| + | |
− | if(this.value === 'enc'){
| + | |
− | lastEdit = elMsg;
| + | |
− | }else{
| + | |
− | lastEdit = elEnc;
| + | |
− | }
| + | |
− |
| + | |
− | updateLast();
| + | |
− | };
| + | |
− | });
| + | |
− |
| + | |
− | elCrypt.onchange = updateCrypt.bind(elCrypt);
| + | |
− |
| + | |
− | if(window.location.hash.length > 1){
| + | |
− | var h = window.location.hash;
| + | |
− | if(h[1] == 'e'){
| + | |
− | elMsg.value = h.substr(2);
| + | |
− | updateEnc();
| + | |
− | }else{
| + | |
− | elEnc.value = h.substr(2);
| + | |
− | updateDec();
| + | |
− | }
| + | |
− | }else{
| + | |
− | updateEnc();
| + | |
− | }
| + | |
− | </script>
| + | |
− | </body>
| + | |
− | </html>
| + | |