すずしんろぐ

読者です 読者をやめる 読者になる 読者になる

すずしんろぐ

人生大逆転を目指す、鈴木俊吾の成長日記

Java 任意の文字列をAESで暗号化・復号化する方法(Cipher)

プログラミング

こんばんは、すずしんです。

今日はJava暗号化復号化について勉強してみました。 JavaではCipherクラスを使うと、比較的簡単に暗号化・復号化ができるようです。 今回の記事では、Cipherクラスを使ってAESで暗号化・復号化する方法についてまとめておきます。

Cipherクラスを使った暗号化・復号化

Cipherクラスは、暗号化および復号化の暗号機能を提供しています。 利用可能な暗号化方式には複数(DES/AES/RSAなど)ありますが、今回はAESで暗号化・復号化することとします。

Cipherオブジェクトを生成するには、CipherのgetInstance()を呼び出して要求された変換の名前を渡します。 この変換というのが暗号化方式です。 変換は、以下の書式で記述されます。

・"algorithm/mode/padding"
・"algorithm"

今回は後者の方式を利用してみます。 AESでCipherオブジェクトを生成するには以下のようにします。

Cipher cipher = Cipher.getInstance("AES");

続いて、Cipherを初期化します。 init(int opmode, Key key)メソッドで暗号化(復号化)モードと秘密鍵(キー)を設定します。

// 暗号化
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.getBytes(), algorithm));
// 復号化
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getBytes(), algorithm));

その後、doFinal(byte[] input)メソッドを呼び出します。 inputには暗号化(復号化)したい文字列をバイト列に変換した値を与えます。 変換後のバイト列が返り値になります。

byte[] encryptBytes = cipher.doFinal(source.getBytes());

CipherManagerクラス

以上を踏まえて、Cipherクラスを使って文字列を暗号化・復号化する機能を持ったクラス(CipherManager)を作ってみました。 暗号化はencrypt()メソッド、復号化はdecrypt()メソッドを使います。 Base64によるエンコード・デコード処理も行っています。

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.Cipher;

public class CipherManager {
    public static String encrypt(String source, String key, String algorithm) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        Cipher cipher = Cipher.getInstance(algorithm);
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.getBytes(), algorithm));
        return new String(Base64.getEncoder().encode(cipher.doFinal(source.getBytes())));
    }
    
    public static String decrypt(String encryptSource, String key, String algorithm) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        Cipher cipher = Cipher.getInstance(algorithm);
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getBytes(), algorithm));
        return new String(cipher.doFinal(Base64.getDecoder().decode(encryptSource.getBytes())));
    }
}

サンプルプログラム

上記のCipherManagerクラスを使って、文字列を暗号化・復号化するサンプルプログラムを作成してみました。 変換元の文字列にはローマ字のみ、日本語のみの2パターンを試してみました。

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

public class CipherTest {
    private static final String KEY = "YKo83n14SWf7o8G5";
    private static final String ALGORITHM = "AES";
    
    public static void main(String[] args) {            
        try {
            String source1 = "This is a cipher test source.";
            String source2 = "これは暗号化テストです。";
            
            String encrypt1 = CipherManager.encrypt(source1, KEY, ALGORITHM);
            String encrypt2 = CipherManager.encrypt(source2, KEY, ALGORITHM);
            String decrypt1 = CipherManager.decrypt(encrypt1, KEY, ALGORITHM);
            String decrypt2 = CipherManager.decrypt(encrypt2, KEY, ALGORITHM);
            
            System.out.println("Source1: " + source1);
            System.out.println("Encrypt1: " + encrypt1);
            System.out.println("Decrypt1: " + decrypt1);
            System.out.println();
            System.out.println("Source2: " + source2);
            System.out.println("Encrypt2: " + encrypt2);
            System.out.println("Decrypt2: " + decrypt2);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException ex) {
            Logger.getLogger(CipherTest.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

実行結果

サンプルプログラムの実行結果は以下のようになりました。 きちんと暗号化と復号化がされているのが分かります。 暗号化後の文字列は何やらすごいことになっていますね。

Source1: This is a cipher test source.
Encrypt1: tMlDW31pOHEjsOHWSIsPaq5cq8/PPkX84d+Ozf6QEME=
Decrypt1: This is a cipher test source.

Source2: これは暗号化テストです。
Encrypt2: Db/EuOpyOz/xX06j0Eju4K51xHRFhivlWD/2TM+qDvCuJs9ViH1j2SWymV/qKoAr
Decrypt2: これは暗号化テストです。