Tuesday, March 27, 2018

Hidden in plain sight: Using Unicode Braille Patterns for message obfuscation

Like the author at glow.li, as soon as I found out that Unicode has support for generating Braille Patterns I knew I'd have to put this capability to use. I took a slightly more practical approach than designing a font using braille (which I'll agree with the author, is delightfully perverse) and instead opted to use Braille as a sort of easy to read 'secret' code.

The use case is this: suppose you want to text your wife to pick up some cream for that nasty rash that recently flared up. You want to text her, and make sure she sees the message loud and clear. Yet, you'd like her nosy co-workers to remain in the dark about your condition. So you both agree to: (a) learn the braille alphabet, and (b) use a new convention in your text messages.

The convention I've implemented is this: any words between two sets of dots are automatically converted to Braille encoded letters. This allows you to compose a text message like so:

With the appropriate Tasker code in place, the following alert is shown when the message comes in:

The Tasker code consists of a trivial set of actions to detect encoded text:

The more interesting part is the JavaScript that converts from plain text to Braille Patterns:

function tToB(text) {

  function toHex(v) {
    var x = v.toString(16);
    return x.length == 1 ? "0" + x : x; 
  }


  var bmap = {
    a: [1], b: [1,2], c: [1,4], d: [1,4,5], e: [1,5], 
    f: [1,2,4], g: [1,2,4,5], h: [1,2,5], i: [2,4],
    j: [2,4,5 ], k: [1,3], l: [1,2,3], m: [1,3,4],
    n: [1,3,4,5], o: [1,3,5], p: [1,2,3,4],
    q: [1,2,3,4,5], r: [1,2,3,5], s: [2,3,4],
    t: [2,3,4,5 ], u: [1,3,6], v: [1,2,3,6], x: [1,3,4,6],
    y: [1,3,4,5,6], z: [1,3,5,6], w: [2,4,5,6]
  };

  var html = "";
  var text = text.toLowerCase();

  for(var i = 0; i < text.length; i++) {
    var c = text[i];
    if(c == ' ') {
      html += "&nbsp;&nbsp;&nbsp;"; 
    } else if(bmap[c]) {
      var val = 0;
      for(var j = 0; j < bmap[c].length; j++) {
        val += (1 << (bmap[c][j]-1));
      }
      html += "&#x28" + toHex(val) + ";"; 
    } else {
      html += "_";
    }
  }

  return html;
}

var matches = text.match(/[.][.](.*?)[.][.]/g);
var html = text;
if(matches) {
  for(var i = 0; i < matches.length; i++) {
    html = html.replace(matches[i], tToB(matches[i].replace(/[.]/g, ''))); 
  }
}

The Unicode standard for Braille Patterns is actually quite clever. The dots in a Braille pattern have a standard numeric index. E, for example, has dots 1 and 5 raised. In Unicode, these indexes correspond to bit positions. In the case of E, the bits enabled would be 10001000. This means that you can use Braille Patterns to represent any 8 bit piece of data, from a letter, to an arbitrary byte in a binary file.

Thanks again to glow.li for the inspiration!

No comments:

Post a Comment