ファイルを暗号化するの巻
実はこのネタ、かなり前にChikayanさんからリクエストがあってずっと構想を練っていたのですが、筆者の怠惰により延び延びになってしまいました。済みません>Chikayanさん。それに、1年も新しいネタを供給しないとは何事か(自戒)。
●はじめに
テキストを多く扱うAVGやRPGを作っていると、その文章がエディタで丸見えになって困ります。そこでファイルを暗号化して読めなくしてしまおう、と言うことです。
あらかじめ断っておきますが、ここで扱う暗号化は「パッと見ただけではわからない」程度の物であり、セキュリティ確保のために使われるような本格的な物ではありませんが、それでいてズブの素人には解析困難であろう手段を提供するつもりです。ただし、シェアウェアのパスワードなどのような、「クラックするな!」的なものに導入するのはそういった理由から(要するにシェアウェアのパスクラックができる人なら余裕で破れそうなレベルだから)おすすめしません。
それからβ版において暗号化がサポートされると言う、大変このページの存在意義を疑う事態になっていますが気にしないものとします(笑)。あくまで独自に暗号化を行いたい人のための講座です。
●暗号化の方法
暗号化とは簡単に言ってしまえば「データを元に戻るように書き換えること」です(この説明じゃ、あまりに簡単すぎて圧縮なども含まれてしまいますが)。では、どのような方法があるでしょうか。
注:暗号化・復元の方法をスクリプトで記述してありますが、以下のことが前提になっています。
*変数dst=暗号化・復元を行った後の文字コード
*変数src= 〃 行う前の文字コード
*変数key=暗号キー
*srcはpeek命令で1バイトずつ読み込んである
*keyは0〜255まで
◇足し算・引き算
"ABC" (65,66,67) |
→ | コード+1 | → | "BCD" (66,67,68) |
"BCD" (66,67,68) |
→ | コード-1 | → | "ABC" (65,66,67) |
任意の数値を足したり引いたりすることで、当然の事ながらコードがずれます。例えば"A"と言う文字は文字コードに直すと65です。これに1を足せば66、つまり"B"になります。1バイトは0〜255までなのでその範囲からはずれたときのフォローをきちんと行えば全ての文字に対応できます。
;暗号化(加減算方式) dst=src+key ;または、dst=src-key ;オーバーフロー対策 dst=dst+256&255 |
この方法で暗号化したものを元に戻すには、説明するまでもないですがさっき足した(引いた)値を引いて(足して)やればよいですね。
;復元(加減算方式) dst=src-key ;または、dst=src+key ;オーバーフロー対策 dst=dst+256&255 |
◇排他的論理和
01001101 | → ← |
10101010 (1の立っているビットは反転される) |
→ ← |
11100111 |
要するにxorであり、HSPの演算記号で言う「^」です。この演算はビットを反転させる作用がありますので、暗号化・復元の両方が同じプログラムで行えます。
;暗号化・復元(排他的論理和) dst=src^key |
◇ビットシフト
10100111 | → | (1ビット右にずらし、はみ出たビットを最上位に持っていく) |
→ | 11010011 |
10100111 | → | (1ビット左にずらし、はみ出たビットを最下位に持っていく) |
→ | 01001111 |
見たまんまです。注意点としては、はみ出たビットをちゃんと後ろ(前)に戻してやらないと暗号化できるデータが制限されてしまいますので、そこの処理をきちんと行ってやる必要があることです。当然の事ながら、逆方向にシフトすれば元に戻ります。
この方法だと暗号化キーが固定になる(もしくは7通りしかない)と言う欠点があるので、他の方法と併用する必要があります。というか、単体で使うとあまりのキーの少なさに(アルゴリズムがバレると)一発で解読されます。つまり、バレバレです。また、下のサンプルも1bitシフト限定です(どうせ対応させても先述の理由で無意味なので)。
;暗号化・復元(ビットシフト・右) ;まずシフトする dst=src>>1 ;はみ出たビットを最上位に持っていく dst+=src&1<<7 ;※当然、dst=src&1<<7+(src>>1)と1行でやっても良い。 ;※dst=src<<7+(src>>1)&255は(わかりやすさの点で)もっと良いだろう。 |
;暗号化・復元(ビットシフト・左) ;まずシフトする dst=src<<1&255 ;はみ出たビットを最下位に持っていく dst+=src>>7 ;※当然、dst=src>>7+(src<<1)&255と1行でやっても良い。 |
◇シャッフル(ビット入れ替え)
00111010 | → | (色に対応した位置に入れ替える) |
→ | 11010010 |
これも見たままですね。この方法だと8bitの暗号化にもかかわらず組み合わせが約4万通りあるので単体でもそれなりに利用価値はありそうですが、順番の作成方法がどうしてもランダムに頼らざるを得ないため、パスを解除できるキーが複数存在することになります(複雑なことをすれば10進数のキーから重複する数値のない8桁の8進数を生成することはできそうですが)。そして、致命的なことに入れ替えた順番を記憶させる=ファイルにパスの情報を含ませないと復元できないという欠点があります。要するに、パスが漏れる可能性が高いと言うことです。
;暗号化テーブルを作成 dim st,8 ;あらかじめ定義しておくこと repeat 8 st.cnt=cnt loop randomize key ;まぁとりあえず repeat 256 a=cnt\8 rnd b,8 c=st.a st.a=st.b st.b=c loop |
;暗号化(ビットシャッフル) repeat 8 a=src&(1<<st.cnt) if a : dst+=1<<cnt loop |
そこで、以下のような方法を用いると良いでしょう。
00111010 | → | (2点を入れ替える) |
→ | 11010010 |
こうすれば、組み合わせは少なくなりますが(それでも2万はあるかと)暗号化を行った時と同じ順で入れ替えを行うことにより復元が可能になるため、パスを記憶させる必要が無くなります。いまいちスマートな記述じゃないのは容赦。
;(テーブル作成部分は上に同じなので省略) dim bit,8 ;あらかじめ定義しておくこと ;暗号化・復元(ビットシャッフル・スワップ方式) repeat 8 a=src&(1<<cnt) if a : bit.cnt=1 :else: bit.cnt=0 loop repeat 4 i=cnt*2 j=cnt*2+1 v=st.i w=st.j swp1=bit.v<<w swp2=bit.w<<v dst+=swp1+swp2 loop |
簡単なところをざっとあげてみましたが、だいたいこんな感じです。手軽に暗号化を行いたいのであれば、最初の2つのうちどちらかのみを採用すればよいです。逆に、ビットシフトは単体で使用するのは無意味すぎです。
●実際に暗号化を行う
それでは実際に暗号化を行ってみましょう。手抜きですがサンプルスクリプトを作ったので、ダウンロードして説明を読んだ上で実行してみて下さい(大して長くないのでここに載せても良かったのですが)。
まずスクリプトの内容ですが、単にファイルをメモリに読み込み、それを1バイトずつ暗号化処理して書き換えているだけでとりわけ難しいことはしていません。暗号化のアルゴリズムはこのページに書かれているスクリプトを参考に指定された範囲を書き直せば変更できます。
試しに↑暗号化サンプル自身を暗号化してみましょう。すると・・・
↑こうなります。画像が小さいですが、完全に意味不明な文字列になっているのがわかるかと思います。今回は排他的論理和で暗号化を行ったので、このファイルを暗号化に書けてやれば元に戻ります。
とりあえず今回はここまでです。次回はもう少し複雑でバレにくい暗号化を考えます。と予告して実行しなかったことが何度あるかわかりませんが(^^;今度こそ本当だから信じて下さいな。