「ゼロ幅文字を使ってテキストに電子透かしのようなものを埋め込む手法」
これは興味深い。
経緯は以下のような感じらしい。
非公開の掲示板の情報が漏洩しているっぽい?
↓
外部からの攻撃ではなさそう。
↓
内部の人間が怪しい。
↓
ユーザー固有の見えない文字を埋め込むようにしてみた。
↓
その後に漏洩した情報をチェック。
↓
コピペ犯人を特定!
で、見えない文字というのが、
UNICODEにある「ゼロ幅文字」というやつらしい。
こんなのあったんだね( ≧▽)ノ”Ω へぇー
こちらのデモを試してみると、
確かにうまく行っていますね。
ところでUNICODEには見えない文字が
これだけあるようです。
結構ありますね。
U+9
U+A
U+B
U+C
U+D
U+20 SPACE
U+85
U+A0 NO-BREAK SPACE
U+2000 EN QUAD
U+2001 EM QUAD
U+2002 EN SPACE
U+2003 EM SPACE
U+2004 THREE-PER-EM SPACE
U+2005 FOUR-PER-EM SPACE
U+2006 SIX-PER-EM SPACE
U+2007 FIGURE SPACE
U+2008 PUNCTUATION SPACE
U+2009 THIN SPACE
U+200A HAIR SPACE
U+2028 LINE SEPARATOR
U+2029 PARAGRAPH SEPARATOR
U+202F NARROW NO-BREAK SPACE
U+205F MEDIUM MATHEMATICAL SPACE
U+3000 IDEOGRAPHIC SPACE
U+180E MONGOLIAN VOWEL SEPARATOR
U+200B ZERO WIDTH SPACE
U+200C ZERO WIDTH NON-JOINER
U+200D ZERO WIDTH JOINER
U+2060 WORD JOINER
U+2061 FUNCTION APPLICATION
U+2062 INVISIBLE TIMES
U+2063 INVISIBLE SEPARATOR
U+2064 INVISIBLE PLUS
U+3164 HANGUL FILLER
U+FFA0 HALFWIDTH HANGUL FILLER
U+FEFF ZERO WIDTH NO-BREAK SPACE
ただ、
透明文字でも幅があると、
空白のように見えるのでうまくないですよね。
そんなわけでゼロ幅な文字が最適ということのようです。
透明でゼロ幅な文字はいくつかあるようなのですが、
上記によれば明示的に「ゼロ幅」となっているのは、
U+200B ZERO WIDTH SPACE
U+200C ZERO WIDTH NON-JOINER
U+200D ZERO WIDTH JOINER
U+FEFF ZERO WIDTH NO-BREAK SPACE
の4つになりそうです。
先のデモのソースコードを読んでみた所、
まさにこの4つの文字を使ってエンコードしていました。
どうやってユーザー名をエンコードして埋め込んでいるかというと、
以下のような感じらしい。
1)入力文字を8ビットな2進表記に変換。文字と文字の間には空白を入れる。
2)「1」に200B、「0」に200C、「空白」に200Dを割り当て、さらに全体をFEFFでつなぐ。
デモでは8ビットまでの前提なので、
U+00~U+FFの内の可読文字、
いわゆるASCII相当の文字だけが使えるようです。
漢字とかだとダメですね。
実際にユーザー名を「HOGE」としてやってみると、
(コードとしては、U+48,U+4F,U+47,U+45 となります)
以下のような感じになりました。
1)の結果
01001000 01001111 01000111 01000101
2)の結果
0-1-0-0-1-0-0-0-,-0-1-0-0-1-1-1-1-,-0-1-0-0-0-1-1-1-,-0-1-0-0-0-1-0-1
※実際は透明&ゼロ幅で見えないので、わかりやすくするために、
200B -> 「1」、200C -> 「0」、200D -> 「,」、FEFF -> 「-」に置き換えてあります。
そんなわけでエンコード後の文字数は結構長くなりますね。
FEFFでつないでいる理由はよく分かりませんが、
「ZERO WIDTH NO-BREAK SPACE」とあるので、
途中で改行させないようにするためかもしれません。
確認はしていませんが、
長いと改行されてしまってバレてしまうのかも?(^_^;)
デモの例では分かりやすくするためということもありそうですが、
ちょっと冗長的な感じがします。
要するにエンコードに使える文字が4つあるので、
埋め込む情報を4進数にして、
0~3にそれぞれゼロ幅文字を単純に割り当てるやり方で良いのかも。
2ビット毎に文字を割り当てるってことですね。
デモの例ではユーザー名でしたが、
ユーザーIDにすれば単なる数値になるはずなので、
32ビット数値とすれば最大16文字に収まることになります。
エンコード後の文字数をより少なくできそうです。