JavaでAES(共通鍵暗号)による暗号化

ヘッダー広告
スポンサードリンク

Javaで共通鍵暗号を利用した暗号化の仕組みについてご紹介致します。
共通鍵暗号には、DES、トリプルDES、AES等いくつかの処理方式が存在するのですが、今回はその中でも良く利用されていて、広く推奨されているAESによる暗号化を記載します。

早速ですが、実際のJavaのコードから確認していきましょう。

AESのJavaコード

暗号化する

●CipherUtil
package test;


import java.security.spec.AlgorithmParameterSpec;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;


public class CipherUtil {

	/*
	 * 暗号化の方法
	 * 暗号化アルゴリズム・・・AES
	 * ブロック暗号のモード・・・CBS
	 * パディング方式・・・PKCS5Padding
	 */

	//暗号化のキーを指定する。
	private static final byte[] ENCRYPT_KEY = "abcdefghijklmnop".getBytes();

	//初期化ベクトル (IV)を指定する。
	private static final byte[] IV_KEY = "0123456789012345".getBytes();

	//外部から呼び出される暗号化メソッド
	public static final String encode(String plainText){
		return encode(plainText,IV_KEY);
	}

	private static final String encode(String plainText,byte[] iv){

		String encryptText = null;

		try {
			//初期化ベクトル (IV)をセットする。
			AlgorithmParameterSpec ivSpec = new IvParameterSpec(iv);

			//暗号化方式、ブロック暗号のモード、パディング方式を指定する。
			Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
			//暗号方式等をセットして、暗号器を生成する。
			cipher.init(Cipher.ENCRYPT_MODE , new SecretKeySpec(ENCRYPT_KEY, "AES"), ivSpec);

			//暗号化対象の文字列を暗号化する。
			byte[] cryptogram = cipher.doFinal(plainText.getBytes("MS932"));

			//暗号化されたデータに対してbase64エンコードを行い、文字列化する。
			encryptText = Base64.getEncoder().encodeToString(cryptogram);

		} catch (Exception e){
			System.out.println(e);
			e.printStackTrace();
		}

		return encryptText;

	}

	public static final String decode(String encryptText){

		String plainText = null;

		try {

			byte[] BaseDecode = null;
			byte[] iv = IV_KEY;

			//暗号化された文字列をbase64デコードを行い、バイト変数に戻す
			BaseDecode = Base64.getDecoder().decode(encryptText);

			AlgorithmParameterSpec ivSpec = new IvParameterSpec(iv);

			//暗号化方式、ブロック暗号のモード、パディング方式を指定する。
			Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
			//暗号方式等をセットして、暗号器を生成する。
			cipher.init(Cipher.DECRYPT_MODE , new SecretKeySpec(ENCRYPT_KEY, "AES"), ivSpec);

			//暗号化済みのバイト変数をデコードする。
			byte[] decoded = cipher.doFinal(BaseDecode);

			plainText = new String(decoded,"Windows-31J");

		} catch (Exception e){
			e.printStackTrace();
		}

		return plainText;

	}

}

暗号化を呼び出すテストコード

●CipherTest
package test;


public class CipherTest {

	public static void main(String[] args){

		String encData = "system-engineerlife.com";
		String encryptData = null;

		System.out.println("暗号化前:" + encData);

		encryptData = CipherUtil.encode(encData);

		System.out.println("暗号結果:" + encryptData);

		encryptData = CipherUtil.decode(encryptData);

		System.out.println("複合結果:" + encryptData);

	}

}

●実行結果

暗号化前:system-engineerlife.com
暗号結果:HpuORpQb7xmwgDLpfYNfapSUQZbKr1f15xLlH/0k7mo=
複合結果:system-engineerlife.com

CipherUtilクラスの使い方としては、暗号したい文字列をCipherUtil.encodeメソッドの引数に設定すれば、暗号化後の文字列が戻り値として返却されます。
逆に複合化したい場合には、暗号化後の文字列をCipherUtil.decodeメソッドの引数に設定することで、暗号化前の文字列が戻り値として返却されます。

CipherUtilクラス内のENCRYPT_KEY変数、IV_KEY変数には、暗号化の鍵となるbyte配列を格納します。
後述しますが、ここの値は重要な文字となりますので、実際に利用する場合には適切な値に変更し、絶対に漏洩しないように管理する必要があります。

実際の実行結果も記載していますが、
このように、暗号化前の文字列「system-engineerlife.com」が、CipherUtil.encodeによる暗号化後には、「HpuORpQb7xmwgDLpfYNfapSUQZbKr1f15xLlH/0k7mo=」という文字列に変更されていることが分かると思います

その後、暗号化後の文字列「HpuORpQb7xmwgDLpfYNfapSUQZbKr1f15xLlH/0k7mo=」を、CipherUtil.decodeを利用すると、「system-engineerlife.com」という暗号化前の文字列が返却されることが分かります。

AES暗号についてとコードの解説

AESとCBCとパディング

AES
 Advanced Encryption Standardの略で、共通鍵暗号において世界的で標準として使われているアルゴリズムになります。
2000年に世界中から暗号アルゴリズムを集って、評価した結果Rijndaelという暗号アルゴリズムが世界標準として選ばれて、AESという名前を付けられました。
AESは、ブロック暗号と呼ばれていて、固定長ビットの平文を暗号化するという仕組みになっています。
そのため、長いデータを暗号化していく際には、ブロック単位で暗号化を繰り返して暗号化していきます。

CBC
 CBC(Cipher Block Chaining mode)はブロック暗号のモードの1つです。
AESの場合は、128ビットずつをブロック長として扱っていて、ブロックごとに暗号化を繰り返して暗号化を実現します。

CBCモードの場合には、1つ前の暗号文ブロックと対象の平文ブロックをXOR(排他論理和)を行って、対象の暗号文を作成していきます。
最初のブロックを作成するときにだけ、初期化ベクトル(IV)が必要になることも重要なので覚えてください。

平文をブロックごとに暗号化していくという特徴から、最終平文ブロックに文字列が128ビットに足りないことがあります。
足りない部分はパディングという文字埋めを行い、128ビットになるように調整します。

解説図

クリックすると別ウインドウにて画像が開かれます。

コード解説

CipherUtilクラスのコード解説をしたいと思います。

まず、private変数のENCRYPT_KEYとIV_KEYについてですが、ENCRYPT_KEY変数はAES暗号化の鍵となるバイト配列を格納します。
今回は分かりやすくなるように16文字(16バイト)の文字列を、getBytesをしようしてバイト型に変換して格納しています。
AESでは、128ビット、192ビット、256ビットの3種類のビット長が想定されていますが、javaでは基本的には128ビットにて作成する必要があります。

続いてIV_KEY変数ですが、CBCモードで暗号化する際に初期ブロックの暗号化を行うために利用する初期化ベクトル(IV)を格納します。
AESのブロック長は、128ビットなので、こちらは必ず128ビットを指定する必要があります。

暗号化・複合化には、Cipherクラスを利用します。
まずはgetInstanceメソッドにて暗号化方式を指定します。今回は、AESのCBCモード、PKCS5Paddingにてパディングという暗号化を行うため、引数に「AES/CBC/PKCS5Padding」を指定しています。

次にinitメソッドにて、暗号化か複合化かを指定、鍵をセット、初期ベクトル(IV)をセットして暗号化・複合化の準備を行います。

最後に、doFinalメソッドにて暗号化したい文字列をバイト化したものを引数として渡してあげれば、暗号化後・複合化後のバイト配列が返却されます。

これがCipherクラスの使い方になります。

最後に、暗号化した結果はバイト型にて返却され、このままだと文字列として扱えないので、base64エンコードを行って文字列化します。
※base64エンコードについては、他のサイトをご参照ください。

ちなみに、base64クラスはJava8から導入されました。これを利用することで簡単にバイト配列を文字列化することが可能です。
複合化する時もbase64でデコードしてからCipherクラスを利用して複合化してあげる必要があります。

以下の記事では、実際にログイン画面等でパスワードを暗号化する方法、照合する方法についてご紹介しております。
是非参考にしてください。
Javaでパスワード登録&ログイン処理を行う方法(AES暗号化)

以上。

フッター広告

スポンサードリンク



シェアする

  • このエントリーをはてなブックマークに追加

フォローする