暗号化という言葉を聞いたことはありますか?
ほとんどの人が暗号化という言葉を知っているでしょう。
プログラミングではパスワードを暗号化したりします。
今回は、JavaでCipherクラスを利用した暗号化についてご紹介します!
記事の信頼性:未経験からIT企業の受託企業へ転職に成功。現役プログラマーの「しう」がCipherを利用したJavaの暗号化についてお伝えします。
暗号化について

暗号化とは、パッと見て他の人からわからないように変換することです!
そして、暗号化したものを解読できるように変換することを復号といいます。
パスワードなどでよく用いられる技術です。
大事な情報が他の人に読まれてしまっては大変ですからね。
暗号化と復号の関係は次のようになります。

暗号方式
暗号方式には大きく分けて2種類あります!
- 共通鍵暗号方式(代表例:AES)←今回利用する方法!
- 公開鍵暗号方式(代表例:RSA)
です。
こちらについては、今後執筆予定です。
Cipherとは?【Javaのクラス】

JavaのCipherクラスは暗号化・復号をするためのクラスです!
暗号化にはAES暗号やRSA暗号があります。
そして、このCipherクラスをJavaで利用することで、暗号方式が変わっても負担が少なく暗号化することができます。
また、暗号化復号用のメソッドも用意されているので便利です。
Javaで暗号化をしてみる

いよいよJavaで暗号化をしていきましょう!
今回は
- CryptServiceクラス
- FileUtilクラス
- Mainクラス
を利用して作成していきます。
それぞれのクラスの役割も説明しているので参考にしてください。
CryptServiceクラス【暗号化のservice】
最初に暗号化をするクラスを作成します!
コードは以下のようになります。
package com.company.service;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.Serializable;
import java.util.Base64;
public class Crypt implements Serializable {
//暗号化用の準備
private Cipher encrypter;
//複号用の準備
private Cipher decrypter;
public Crypt(byte[] secretKey, byte[] ivs) throws Exception{
IvParameterSpec ivParameterSpec = new IvParameterSpec(ivs);
SecretKeySpec key = new SecretKeySpec(secretKey, "AES");
encrypter = Cipher.getInstance("AES/CBC/PKCS5Padding");
encrypter.init(Cipher.ENCRYPT_MODE, key, ivParameterSpec);
decrypter = Cipher.getInstance("AES/CBC/PKCS5Padding");
decrypter.init(Cipher.DECRYPT_MODE, key, ivParameterSpec);
}
//暗号化処理を実行するメソッド
public String encrypt(String text) throws Exception{
byte[] crypt = encrypter.doFinal(text.getBytes());
byte[] str64 = Base64.getEncoder().encode(crypt);
return new String(str64);
}
//複合処理を実行するメソッド
public String decrypt(String str64) throws Exception{
byte[] str = Base64.getDecoder().decode(str64);
byte[] text = decrypter.doFinal(str);
return new String(text);
}
}

ややこしくてこんなのわからないよ。。。



大丈夫! 一つ一つ、丁寧に説明していくで!
それでは、解説をしていきます。
IvParameterSpec ivParameterSpec = new IvParameterSpec(ivs);
では、暗号化のスタートブロックの初期値を設定しています。
暗号化時にはbyte型に変換してブロックごとに何度も暗号化します。(CBCモードという)
その時、最初の暗号化で変換する時に利用するものと知っておいてください。
次に、暗号化の準備をしていきます。
SecretKeySpec key = new SecretKeySpec(secretKey, "AES");
共通鍵暗号の種類(AES)と解読キーのセットを作成しています。
encrypter = Cipher.getInstance("AES/CBC/PKCS5Padding");
encrypter.init(Cipher.ENCRYPT_MODE, key, ivParameterSpec);
decrypter = Cipher.getInstance("AES/CBC/PKCS5Padding");
decrypter.init(Cipher.DECRYPT_MODE, key, ivParameterSpec);
ここでは
- Encrypter : 暗号化の準備
- decrypter : 復号の準備
をしています。
今回は、AES/CBC/PKCS5Padding を指定していますが
DESやRSAなどの種類も指定できます。
使用できる種類についてはこちらの公式リファレンスに記載してあります。
最後に、暗号・復号処理を実行するメソッドが書いてあります。
//暗号化処理を実行するメソッド
public String encrypt(String text) throws Exception{
byte[] crypt = encrypter.doFinal(text.getBytes());
byte[] str64 = Base64.getEncoder().encode(crypt);
return new String(str64);
}
doFinalメソッドでは、引数にバイト型を渡す必要があります。
そのため、text.getBytes()を引数にしています。
また、
byte[] str64 = Base64.getEncoder().encode(crypt);
では、文字化け対策としてエンコーディングをしています。
復号のメソッドでは、デコーディングしてから復号して、変換した文字列をreturnで返しています。
FileUtilクラス【保存用のクラス】
次に暗号キーを保存しておくためのクラスを作成します!
package com.company.service;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
//暗号キーやIVを保存しておくために使うユーティリティ
public class FileUtil {
public static void writeBytes(byte[] b, String path){
try (ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(path))) {
o.write(b);
}catch (Exception e) {
e.printStackTrace();
}
}
public static byte[] readBytes(String path){
byte[] b = new byte[16];
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(path))) {
in.read(b, 0, 16);
}catch (Exception e) {
e.printStackTrace();
}
return b;
}
}
- writeBytesメソッド:書き込み
- readBytesメソッド:読み込み
をおこないます。



なんで暗号キーを保存しておく必要があるんだろう



会員制のサイトでパスワードを登録したことはあると思うねん。



その登録したパスワードは、サイトにログインするたびに使うやんか。



やから、パスワードの内容を記録しておく必要があるねん。
ちなみに、実務ではパスワードやログインIDはファイル上でなく、データベース上に登録されます。
そのため、DBから該当パスワードを読み込む作業も必要になってきます。
Mainクラス【暗号化をしよう!】
最後にMainクラスについてです!
package com.company;
import com.company.service.Crypt;
import com.company.service.FileUtil;
public class Main {
public static void main(String[] args) {
byte[] iv = "abcdefgh".getBytes();
byte[] key = "siu_2021_key_".getBytes();
FileUtil.writeBytes(iv, "iv");
FileUtil.writeBytes(key, "secret");
System.out.println("IV(スタートブロック用の初期値) =" + new String(iv) + "(" + iv.length + "byte)");
System.out.println("暗号解読キー" + new String(key) + "(16byte)");
String source = "暗号化したい文章";
String result = "";
try{
Crypt c = new Crypt(FileUtil.readBytes("secret"), FileUtil.readBytes("iv"));
result = c.encrypt(source);
}catch(Exception e){
e.printStackTrace();
}
System.out.println("暗号=" + result);
try{
Crypt c2 = new Crypt(FileUtil.readBytes("secret"), FileUtil.readBytes("iv"));
result = c2.decrypt(result);
}catch(Exception e){
e.printStackTrace();
}
System.out.println("複合=" + result);
}
}
先ほど用意したCryptクラスとFileUtilクラスを利用していきましょう
byte[] iv = "abcdefgh".getBytes();
byte[] key = "siu_2021_key_".getBytes();
iv(初期化ベクトル)とキーをバイト型で作成しています。
今回は、簡略化するためにiv(初期化ベクトル)をabcdefghとしています。
しかし、本来であればrandomクラスなどを使用して乱数をiv(初期化ベクトル)に設定しなければいけません。
こちらについては、今後執筆予定です。
FileUtil.writeBytes(iv, "iv");
FileUtil.writeBytes(key, "secret");
作成したiv(初期化ベクトル)とキーをFileUtilクラスを利用してファイルに保存します。
次に、Cryptクラスを利用して、保存したivとキーを利用して暗号化をおこないます。
Crypt c2 = new Crypt(FileUtil.readBytes("secret"), FileUtil.readBytes("iv"));
result = c2.decrypt(result);
また、System.out.printlnで暗号化した文字列を出力した後には、Ctyprクラスを使用して復号をおこない平文にします。
復号した文字列も出力出来たら終了です。
上手く実行できれば次のように表示されます。


実際に利用した時のエラー【暗号化の困りごと】


「しう」が実際に使っていて遭遇したエラーについても記載しておきます!
ここでは
- AESの指定間違い
- Stringからbyteへの変換ミス
についてお伝えします!
AESの指定間違い
キーや暗号方式の指定間違いでエラーが出ることもあります。
会社で暗号化のメソッドを使う場合は、暗号方式を変えると
BadPaddingException
というエラーが出ました。
「AES/CBC/PKCS5Padding」 と指定しないといけない部分をAESと指定していたことが原因でした。
そこに気付かず解決までに数時間以上かかってしまいました。。。
(自分のPCではAESで暗号化しても問題なく動作しました)
Stringからbyteへの変換ミス
ググったところ、String型からbyte型への変換でミスをしているとエラーが発生することも多いようです。
型の指定ミスだと文法エラーでわかりやすいです。(赤線でアラートが出るため)
しかし、処理の途中で変換もれなどある場合は気づきにくいです。
暗号化・復号時にはその準備段階でミスもしていないか気を付けましょう。
まとめ
いかがでしたか?
今回は
- cipherとは?
- 暗号化について
- Javaで暗号化をしてみる
の順に紹介しました。
暗号化はとっつきにくい分野ではありますが、JavaではCipherクラスを利用することができます。
上手くできると達成感も味わえるので、頑張ってみてください!
参考文献など
☟あわせて読みたい 「しう」のオススメブログ






コメント