前章で述べた通り、あのままではバイナリエディタで値を変更したら簡単にセーブデータを変更されてしまいます。
そこで、暗号化してはどうかという話につながりそうですが、暗号化の必要はありません。
セーブデータの記録の仕方を複雑にしたり暗号化したりしなくとも、「セーブデータが改竄されたかどうか」さえ分かればいいのです。
大袈裟な話先ほどの章のように
HP = 200 MP = 100 所持金 = 1000 経験値 = 1000 |
のようにテキストで保存してもいいのです。
ユーザーがそのセーブデータを開いて
「経験値 = 2000」
のように改竄したとしましょう。
改竄されたデータだと分かればゲームに適用しなければいいのですから、改竄チェックさえすればいいことが分かります。
しかし、どうやって改竄されたかどうかを判定しましょう?
ここで、「ハッシュ値」というものを使います。
「ハッシュ値」ってなんだ??と思う人もいるかもしれません。
詳しいことはwikipediaに譲ることにしますが、以下、簡単に説明します。
ハッシュ値とは、ハッシュ関数という特定の計算式で、ある値を別に値に対応付けた値のことです。
少し分かりにくいので、たとえ話をしてみましょう。
先ほどの、
HP = 200 MP = 100 所持金 = 1000 経験値 = 1000 |
というデータは、データ本体のみ出力しているので、どこかが改竄されても改竄されたかどうかがわかりませんでした。
しかし、全ての値の合計を最後に追加してみるとどうでしょう。
HP = 200 MP = 100 所持金 = 1000 経験値 = 1000 合計 = 2300 |
HP + MP + 所持金 + 経験値 = 2300 です。合計値を最後に追加しました。
もし、ユーザーが「経験値 = 2000」のように改竄したならば、
HP = 200 MP = 100 所持金 = 1000 経験値 = 2000 合計 = 2300 |
セーブデータはこのようになることでしょう。しかしこれでは合計値と合いません。
このように、どこかの値を変更したらどこかの値も一緒に変わるような仕組みを取り入れれば、改竄されたかどうかが分かりそうです。
今は丁寧に説明を付けていますから、見ればだいたい合計値も一緒に変更しないといけなさそうだと想像はつきますがデータが
こんな風に並んでいるだけだと、ユーザーはまさか経験値の値を変えたら後ろのデータも変えないといけないなんて思いませんよね。
しかし、データが 1:1 で対応していたら、いずれ解析されてしまうかもしれません。
経験値1000を2000にしたら、合計値2300が3300になり、
経験値2000を3000にしたら、合計値3300が4300になっていると、どういう対応になっているのか大体想像が付きます。
では、最後に記録するデータを「合計」から例えば「合計を79で割った余り」にしてはどうでしょう。
仮に「合計を79で割った余り」を「ハッシュ値」と呼ぶことにします。
すると3300を79で割った余りは61ですから
HP = 200 MP = 100 所持金 = 1000 経験値 = 2000 ハッシュ値 = 61 |
となります。もし、経験値が2000から3000になったとすると、合計である4300を79で割った余りは34ですから
HP = 200 MP = 100 所持金 = 1000 経験値 = 3000 ハッシュ値 = 34 |
となっていなければおかしいです。
ユーザーはこの「合計を79で割った余り」という計算式を知りませんから、改竄しようにも、改竄が出来ません。
どこか特定の場所のみ値が変更されていたらハッシュ値と合わなくなりますから、改竄チェックをする私たちはそこから改竄されたかどうか判断できます。
また、セーブデータからはハッシュ値が計算出来ましたが、ハッシュ値からはセーブデータを計算することができません。
このような不可逆なハッシュの計算方法を「一方向ハッシュ」と呼びます。
(ネットでパスワードを入力することがあると思いますが、データセンターに保存されているパスワードのデータは大抵このような一方向ハッシュで保存されています。
保存したハッシュ値からパスワードが予測できてしまっては危険ですからね)
ハッシュ値の計算方法は非常に沢山ありますが、正直なんだって構いません。
大袈裟な話、先ほどの「合計を79で割った余り」をハッシュ値代わりに使っても、それだけで改竄される可能性はグンと減ることでしょう。
しかし、ユーザーがセーブデータを解析し、最後の4バイトにハッシュ値が埋め込まれていることを突き止めたとしたら、
79分の1の確率で改竄されてしまいます。
ですから、ここでは、世界で広く使われている有名なハッシュ関数を紹介します。
有名なハッシュ関数に「MD5」や「SHA」というハッシュ関数があります。
これも詳しいことはWikipediaに譲りますが、デジタル署名や認証に広く使われていて、アメリカ政府の標準ハッシュ関数に指定されているようです。
例えばMD5は128bitで表現するハッシュ関数であり「340282366920938463463374607431768211456種類」のハッシュ値が存在する非常に解析の困難なハッシュ関数です。
次の章で、MD5を用いたハッシュ値の利用方法について紹介します。
※ 余談 ※
「セーブデータ 解析」などでググるとセーブデータの解析を手伝うツールが出てきたり、様々なゲームのセーブデータの情報を見ることが出来ます。
こちらのページでグランツーリスモ3のセーブデータの構造が紹介されていました。ハッシュの計算にはCRC32が使われているようです。
- Remical Soft -