【Java】セーブデータの暗号化

2018年3月11日

本稿は、セーブデータを暗号化し、ユーザーに書き換えられないファイルを作成する方法を紹介します。

セーブデータを容易に書き換えられると、ユーザーが簡単に不正をすることができてしまいます。

例えば、ゲームのハイスコアをテキストで書き出すと人間にも簡単に内容がわかるので、そのファイルを改変すると簡単にハイスコアをとったことにできます。

これを防ぐために、人間にわかりにくい文字列にしてしまって、書き換えられないようにしましょう。

今回はAESの暗号化アルゴリズムで暗号と複合をやっていきます。

書き出しファイルの暗号化

ファイルの暗号化はJavaのクラスを利用することで簡単に実現できます。

javax.cryptoパッケージのCipher系クラスを利用しましょう。

CipherOutputStreamを別のストリームと一緒に利用することで、簡単に書き出しファイルの暗号化を施せます。

それではサンプルをご覧ください。

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;

public class Test {

	public static void main(String[] args) throws IOException, InvalidKeyException
	, NoSuchAlgorithmException, NoSuchPaddingException
	, IllegalBlockSizeException, BadPaddingException {

		String key = "angoukeymojiretu";//暗号キー文字列128bit
		String algorithm = "AES";
		Cipher c = Cipher.getInstance(algorithm);
		c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.getBytes(), algorithm));//暗号化モードで初期化
		String value = "あいうえお";//暗号化対象の文字列
		try(FileOutputStream f = new FileOutputStream("test.txt");
				BufferedOutputStream b = new BufferedOutputStream(f);
				CipherOutputStream out= new CipherOutputStream(b, c)){
			out.write(value.getBytes());
		}
	}
}
実行結果

中身が意味不明の文字列で保存されました。

これだと、何が記述されているか判断できないと思います。

暗号ファイルを複合して読み込む

暗号化ファイルを複合して読み込む場合はCipherInputStreamを利用します。

先ほど作成したわけのわからない文字列を複合して「あいうえお」を表示できれば成功です。

ファイルの中身をもう一度確認しておきましょう。

test.txt

こちらが複合サンプルです。

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;

public class Test {

	public static void main(String[] args) throws IOException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
		String key = "angoukeymojiretu";//複合キー文字列
		String algorithm = "AES";
		Cipher c = Cipher.getInstance(algorithm);
		c.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getBytes(), algorithm));//複合化モードで初期化
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		byte[] data = new byte[1024];
		try(FileInputStream f = new FileInputStream("test.txt");
				BufferedInputStream b = new BufferedInputStream(f);
				CipherInputStream in= new CipherInputStream(b, c)){
			while(true) {
				int num = in.read(data);
				if ( num == -1 ) break;
				out.write(data, 0, num);
			}
		}
		String str = new String(out.toByteArray());
		System.out.println(str);
	}
}
実行結果

あいうえお

データが複合されてあいうえおが表示できました。

暗号化キーと複合化キーは同じにしなければなりません。

これで気休め程度にセーブデータの暗号化ができるようになりました。

平文で保存するよりは安心です。

Java

Posted by nompor