読めないデータ
ここにある情報は、一般的で簡単な暗号化であり、 重要なデータの管理に利用出来るほど強力なものではないことを お断りしておきます。m(_ _)m

■暗号化の理由

シミュレーション、アドベンチャー、RPGなど「プレイするのに時間のかかるゲーム」では、 大抵の場合「セーブ機能」なるものがついていて、一旦ゲームを中断しても再度 同じ場所、あるいはその付近からゲームを再開することができます。
この時にはセーブデータをどこかに保存しておかなければなりません。しかも
内部の情報をファイルとして保存する=そのファイルを見られる可能性がある
ということを考えておかなくてはなりません。
データが自由に変えられてしまっては、ゲームの面白さが殺がれてしまいます。 そこで、データの秘匿化を行うわけです。
ゲームのプレイヤーがコンピュータに詳しくない場合は、拡張子を変更しておくだけでも 十分データの秘匿になりますが、ここは一つ、人間には読めない形式で保存することにしましょう。

■読めるデータ、読めないデータ

読めるデータの代表的なものは、テキスト形式ですね。
数あるゲームソフトの中には、
[SaveData1]
position=55 42 100
level=22 16 22
hp=208 112 240
hpmax=208 112 240
 ・
 ・
 ・
などという、もう変えてください!!と言わんばかりの(^^;  セーブデータを .ini ファイルで出力するようなソフトもあります。
また、「バイナリそのまんま」も読める形式の1つとして数えられるでしょうか。
00 05 00 09 00 07 00 01 00 02 00 03 ・・・
これもバイナリエディタを使えば簡単に変更することができてしまいます。

読めない形式の代表格は「ランダムコード」でしょう。
バイナリエディタで見ると、一見無意味な記号の羅列が書いてあるように見えるものです。
XEVNISのセーブデータを見て頂ければ判ると思います。
あとは、「データ圧縮」ですね。
独自の方法で圧縮を掛けると、専用の展開ルーチンを見つけない限り読むことは出来ません。 セーブデータの解析を趣味にするような方には、どうやっても見破られてしまいますが・・・。

■Step1:データを読めなくする

暗号化は、「元に戻せる」ということが第1条件です。元のデータを1バイトずつ取り出して 変換していきます。データの取りだしには peek / poke、変換にはXORや加減算などが適しています。 (XORの説明は、「All About Operator」を参照してください) 加算や減算を行った際には、必ず1バイトの範囲内に収まるように & 演算子で調節します。
これらの演算に rnd 命令を使用し、乱数を含ませるようにすると完全にランダム(に見える)データを 生成することが出来ます。

■Step2:データを変えると警告が

Step1で読めなくしたデータでも、むりやリ値を変更すると、元の値もしっかり変わってしまい 暗号化の意味があまりありません。そこで、データが変更されたかどうかをチェックする値を セーブデータに含ませることにします。
これは、変換前(あるいは変換後)のバイナリ値を全部加算して、一定の範囲内に収まるように したもので、逆変換時に計算した結果と、このチェックの値が異なればエラーを出してファイルを 読み込まない、といった処理を行うことが出来ます。

■Step3:データを変えられなくする

チェックの値を記録しても、その値の計算方法を見破られると、やはり簡単にデータの変更が 行われてしまいます。こんな事態を避けるには、「数値をいったんテキストに変換して、 ノートパッド命令でリスト化し、保存する」という方法を取ることが出来ます。
普通の「セーブデータ書き換えツール」では、「○○バイト目が△△の情報」といった<固定的な情報>を 格納し変更しているので、数値の桁数によってデータが保存される位置が移動する テキストデータでは、普通の32ビット整数を書き連ねたものより、ファイルの変更が各段に難しくなります。

■サンプルソース

言葉で説明してもあまり意味が無い&わかりにくいので、ソースを載せます。
上の文章を読まなくても、このソースをそのまま使えば暗号化できます。

#define 鍵 5520

;↑暗号化時の「鍵」の設定。(500〜10000程度)
;この値を変えると、暗号化の乱数が変更されます。
;違う「鍵」で暗号化されたデータは、読めません。


	title "暗号化フンプル"

	dialog "*",16 : if stat=0 : end
	fln=refstr

	exist fln:fsize=strsize
	sdim buf,fsize:bload fln,buf,fsize

	getstr disfln,fln,0,'.':ts=disfln+".enc"
	if ts=fln : goto *DLOAD :else: goto *DSAVE
end


*DLOAD
	gosub *ENCLOAD
	bsave disfln+".dec",buf,fsize
	dialog "解読が淑了しました|"
end

*DSAVE
	disfln=disfln+".enc":gosub *ENCSAVE
	dialog "変換が淑了しました|"
end


;/////////////
;暗号化ルーチン。buf に変換元のデータを読み込んでおき、
;出力先のファイル名を disfln に設定しておいてください。

*ENCSAVE
	strlen fsize,buf:alloc wbuf,fsize+6

	wbuf="hec":poke wbuf,3,0x1A
	;↑ヘッダの設定。暗号化ファイルかどうかをここで見分ける。

	randomize:rnd t,255:randomize t
	poke wbuf,4,t:check=0
	;↑乱数の初期化。

	repeat fsize
		peek t,buf,cnt:check=check+t&255
		rnd c,鍵:c=t+c&255:poke wbuf,cnt+6,c
	loop
	;↑暗号化の「核」部分。データの変換を行いながら
	;チェック値の計算を行う。

	poke wbuf,5,check		;チェック値の書き込み

	bsave disfln,wbuf,fsize+6
	alloc wbuf,64			;メモリの節約
return


;/////////////
;暗号解読ルーチン。fln に変換元のファイル名を設定してください。
;buf にデータが読み込まれます。データの変更が認められた場合は
;エラーを出して終了します。

*ENCLOAD
	exist fln:fsize=strsize
	alloc wbuf,fsize:bload fln,wbuf,fsize
	fsize-=6:alloc buf,fsize

	strmid ts,wbuf,0,3
	if ts!"hec" : dialog "暗号化されていません":return
	;↑ヘッダの読み込み。ファイル形式が違うと読み込まない

	peek t,wbuf,4:check=0:randomize t
	;↑乱数の初期化。

	repeat fsize,6
		peek t,wbuf,cnt
		rnd c,鍵:c=t-c&255:poke buf,cnt-6,c
		check=check+c&255
	loop
	;↑暗号化の「核」部分。データの変換を行いながら
	;チェック値の計算を行う。

	peek t,wbuf,5 : if t!check : dialog "データが変郊されています":alloc buf,64
	alloc wbuf,64			;メモリの節約
return

■そのあとに

上のサンプルは、非常に簡単なものです。
とりあえず変更できないようにはなりますが、これ以上の強度が必要な場合は、各個で強化を行ってください。