JavaScript プログラミング | |
自学自習システム作成 |
8.暗号化
練習問題のページもテストのページも表示しているページのHTMLソースを見ると隠しフィールドに答えを設定しているので答えがわかってしまう。答えをJavaスクリプトとして別(外部)ファイルにすることも考えられるが、このファイルを見ようと思えば見ることができてしまう。
あまり厳密に答えを隠す必要もないのだが、ある程度見られない(知られない)方法となると答えを暗号化することが考えられる。
隠しフィールドには暗号化した答えを設定しておく。解答チェックのときに復号化して正誤判定を行う。
KOTAE | → 暗号化 → ← 復号化 ← |
4b4f544145 |
上記は各文字を単に文字コードにしただけであるが、ちょっと見ただけではわかりにくいだろう。ここではこの程度でもかまわないだろうが、複合化するときに2文字ずつ取り出して文字に変換する必要がある。暗号化と同じように1文字ずつ取り出せる方がcharAtメソッドが使えて便利である。
答えは英数字などの半角文字だけでなく、漢字などの全角文字もある。全角文字に関しては、クッキーのところでも使用している関数escapeとunescapeを使うことにする。関数escapeで"漢字"を変換すると
%u6F22%u5B57 というユニコード(unicode)になる。また、英数字以外の記号文字は文字コードに変換される。
(1) 文字をn文字ずらす
1文字ずらした場合、A→B、B→C、・・・という要領である。ただし、文字コードは次のようになっているので境目の文字については別の処理が必要になる。
文字コード表
暗号化の処理の手順としては、@関数escapeでコード化する。An文字ずらす処理をする。である。復号化はその逆の手順である。暗号化は関数toAngou、復号化は関数toCharとして作成する。
次にサンプルのHTMLリストを示す。
<HTML> <HEAD> <TITLE>暗号化テスト</TITLE> </HEAD> <BODY><SCRIPT language="JavaScript"> <!-- key = 1; // ずらす数 function toAngou(str){ // 暗号化 str2 = ""; str = escape(str); // コード化 for(nn = 0; nn < str.length; ++nn){ cd = str.charAt(nn).charCodeAt() + key; // コードをずらす if(cd >= 0x7f) cd = cd - 0x5f; str2 = str2 + String.fromCharCode(cd); } return str2; } function toChar(str){ // 復号化 str2 = ""; for(nn = 0; nn < str.length; ++nn){ cd = str.charAt(nn).charCodeAt() - key; // コードをずらす if(cd <= 0x1f) cd = cd + 0x5f; str2 = str2 + String.fromCharCode(cd); } str2 = unescape(str2); // コード化 return str2; } //--> </SCRIPT> <P>暗号化テスト</P> <FORM><INPUT size="30" type="text" name="STR1"><BR> <INPUT type="button" value="暗号化↓" onclick="STR2.value=toAngou(STR1.value);"><BR> <INPUT size="50" type="text" name="STR2"><BR> <INPUT type="button" onclick="STR3.value=toChar(STR2.value);" value="複合化↓"><BR> <INPUT size="30" type="text" name="STR3"> </FORM> </BODY> </HTML>
グローバル変数keyがコードをずらす大きさである。charAtメソッドで1文字取りだし、charCodeAtメソッドで文字コードに変換している。
暗号化では各文字コードに変数keyを加算し、復号化では逆に変数keyを減算している。
暗号化では、コードが0x7F以上は特殊な文字となるので0x5Fを減算してコード0x20からの文字になるようにしている。同じように復号化ではコード0x1F以下は特殊な文字となるので0x5Fを加算している。
123漢字ABC | → 暗号化 → ← 復号化 ← |
234&v7G33&v6C68BCD |
(2) 論理演算による暗号化
論理演算のうち、排他的論理和(Ex-OR)演算を使うと1度目の演算で別の値になり、さらに同じ演算でもとの値に戻る。例えば、文字A(文字コード0x41)をキー(パスワード)Z(文字コード0x5A)で演算すると次のようになる。
'A' = 0x41 = 0100 0001(2) 'Z' = 0x5A = 0101 1010(2)
排他的論理和
入力 出力 A B Y 0 0 0 0 1 1 1 0 1 1 1 0 ↓
Ex-OR)0x41 = 0100 0001
0x5A = 0101 10100x1B = 0001 1011
Ex-OR)0x1B = 0001 1011
0x5A = 0101 10100x41 = 0100 0001 0x41を演算すると
0x1Bが求められる。
↓
0x1Bを演算すると
0x41が求められる。
文字の範囲は0x20〜0x7E(文字コード表参照)であるからこの計算のように結果が0x1Bという範囲外になると不都合がある。ここでは、下位4ビットだけを演算し、上位4ビットはそのままとする。関数Angouとして作成する。
次にサンプルのHTMLリストを示す。
<HTML> <HEAD> <TITLE>暗号化テスト</TITLE> </HEAD> <BODY><SCRIPT language="JavaScript"> <!-- function Angou(str){ keyw = 0x05; str2 = ""; for(nn = 0; nn < str.length; ++nn){ asc = str.charAt(nn).charCodeAt(); // 文字コード asc = asc ^ keyw; // 排他的論理和 if(asc == 0x7f) // 0x7fはダメ asc = asc ^ keyw; // 排他的論理和(元に戻す) str2 = str2 + String.fromCharCode(asc); } return str2; } //--> </SCRIPT> <P>暗号化テスト</P> <FORM><INPUT size="30" type="text" name="STR1"><BR> <INPUT type="button" value="暗号化↓" onclick="STR2.value=Angou(escape(STR1.value));"><BR> <INPUT size="50" type="text" name="STR2"><BR> <INPUT type="button" value="複合化↓" onclick="STR3.value=unescape(Angou(STR2.value));"><BR> <INPUT size="30" type="text" name="STR3"> </FORM> </BODY> </HTML>
暗号化と複合化の関数は1つになったが、呼び出すときに暗号化のときと復号化のときで違うようになってしまった。
暗号化 Angou(escape(文字列));
復号化 unescape(Angou(文字列));
排他的論理和の計算の後、文字コードが0x7Fの場合はもう一度計算して元に戻している。0x7Fには文字が割り当てられていないからである。
123漢字ABC | → 暗号化 → ← 復号化 ← |
476 p3C77 p0G02DGF |
(3) 暗号の強化
暗号はキー、すなわちパスワードによって意味のわからない文字列に変換を行う。上のサンプルで示した排他的論理和を利用した暗号化の手法は一般的に知られているものであり、そのキーが0x05というデータ1つだけなので比較的容易に解読できてしまう。
暗号を強化するとは、より解読しにくいものにすることで、キーが1つよりは2つ、2つよりは3つというように多くなるほど解読しにくいものになる。
ここでは、2つ以上のキーが設定できるように上の排他的論理和を利用した暗号化サンプルを変更する。
次にサンプルのHTMLリストを示す。
<HTML> <HEAD> <TITLE>暗号化テスト</TITLE> </HEAD> <BODY><SCRIPT language="JavaScript"> <!-- function Angou(str){ keyw = "JavaScript"; // キー pt = 0; // キーのけた用 str2 = ""; for(nn = 0; nn < str.length; ++nn){ asc = str.charAt(nn).charCodeAt(); // 文字コード keyw2 = keyw.charAt(pt).charCodeAt() & 0x0F; // pt番目の文字の下位4ビット ++pt; if(pt >= keyw.length) // キー終了 pt = 0; asc = asc ^ keyw2; // 排他的論理和 str2 = str2 + String.fromCharCode(asc); } return str2; } //--> </SCRIPT> <P>暗号化テスト</P> <FORM><INPUT size="30" type="text" name="STR1"><BR> <INPUT type="button" value="暗号化↓" onclick="STR2.value=Angou(escape(STR1.value));"><BR> <INPUT size="50" type="text" name="STR2"><BR> <INPUT type="button" value="複合化↓" onclick="STR3.value=unescape(Angou(STR2.value));"><BR> <INPUT size="30" type="text" name="STR3"></FORM> </BODY> </HTML>
キーになる文字列を1文字ずつ取り出して、その下位4ビットのデータを暗号化(復号化)のキーにしている。
123漢字ABC | → 暗号化 → ← 復号化 ← |
;35$v5D;2!u4D44B@J |
注意 このサンプルのキーのようにJavaScriptという単語は最初の2〜3文字がわかるとJava, JavaScript, JavaLangage,・・・など連想できてしまうので、良いキーとはいえない。キーには単語が連想できないようなでたらめな文字列がよい。
JavaScript プログラミング | Copyright © 2003 Hiroshi Masuda |