MENU
👇しうが厳選・おすすめのブログ!
しう
【テニス好きブロガー】 
テニス、読書が好きです。IT企業で学んだこともブログに書いています。高校教諭(テニス部顧問)→IT企業。テニス歴12年。人生をより有意義なものにしたいと思い、ブログを書き始めました。Twitterもしています。
アーカイブ

Javaで暗号化・cipherの活用方法とは?【しうの備忘録】

Java Cipher 暗号化

暗号化という言葉を聞いたことはありますか?

 

ほとんどの人が暗号化という言葉を知っているでしょう。


プログラミングではパスワードを暗号化したりします。

 

今回は、JavaでCipherクラスを利用した暗号化についてご紹介します!

記事の信頼性:未経験からIT企業の受託企業へ転職に成功。現役プログラマーの「しう」がCipherを利用したJavaの暗号化についてお伝えします。

目次

暗号化について

Java Cipher 暗号化

暗号化とは、パッと見て他の人からわからないように変換することです!

 

そして、暗号化したものを解読できるように変換することを復号といいます。

 

パスワードなどでよく用いられる技術です。

大事な情報が他の人に読まれてしまっては大変ですからね。

 

暗号化と復号の関係は次のようになります。

暗号方式

暗号方式には大きく分けて2種類あります!

  • 共通鍵暗号方式(代表例:AES)←今回利用する方法!
  • 公開鍵暗号方式(代表例:RSA)

です。

 

こちらについては、今後執筆予定です。

Cipherとは?【Javaのクラス】

Java Cipher 暗号化

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);
    }
}

 

PC好きな一郎君

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

しう

大丈夫! 一つ一つ、丁寧に説明していくで!

それでは、解説をしていきます。

 

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メソッド:読み込み

をおこないます。

 

PC好きな一郎君

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

しう

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

 

しう

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

しう

やから、パスワードの内容を記録しておく必要があるねん。

 

ちなみに、実務ではパスワードやログイン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クラスを使用して復号をおこない平文にします。


復号した文字列も出力出来たら終了です。

 

上手く実行できれば次のように表示されます。

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

Java Cipher 暗号化

「しう」が実際に使っていて遭遇したエラーについても記載しておきます!

 

ここでは

  • AESの指定間違い
  • Stringからbyteへの変換ミス

についてお伝えします!

AESの指定間違い

キーや暗号方式の指定間違いでエラーが出ることもあります。

 

会社で暗号化のメソッドを使う場合は、暗号方式を変えると

BadPaddingException

というエラーが出ました。

 

「AES/CBC/PKCS5Padding」 と指定しないといけない部分をAESと指定していたことが原因でした。

 

そこに気付かず解決までに数時間以上かかってしまいました。。。

(自分のPCではAESで暗号化しても問題なく動作しました)

Stringからbyteへの変換ミス

ググったところ、String型からbyte型への変換でミスをしているとエラーが発生することも多いようです。

 

型の指定ミスだと文法エラーでわかりやすいです。(赤線でアラートが出るため)

しかし、処理の途中で変換もれなどある場合は気づきにくいです。

 

暗号化・復号時にはその準備段階でミスもしていないか気を付けましょう。

まとめ

いかがでしたか?

 

今回は

  • cipherとは?
  • 暗号化について
  • Javaで暗号化をしてみる

の順に紹介しました。

 

暗号化はとっつきにくい分野ではありますが、JavaではCipherクラスを利用することができます。

 

上手くできると達成感も味わえるので、頑張ってみてください!

参考文献など

 

解答・解説に間違いがあれば、お手数ですが下にあるコメントもしくはtwitterよりご連絡ください。

 

☟あわせて読みたい 「しう」のオススメブログ

あわせて読みたい
Udemy・新規登録方法(セールも)【プログラミングのスキルアップに】 Twitterでもよく見かけるUdemy(ユーデミー)というサイトをご存じでしょうか?   Udemyは、数千円~数万円程度でITに関する講座を見ることができるサイトです。 わかり...
あわせて読みたい
リモートワーク用ディスプレイを買ってみた【BenQ GW2480T】 最近、ついにリモートワーク用のディスプレイを購入しました!   リモートワーク用のディスプレイについて興味があるんだけど実際のところどうなんだろう? 今回は、実...
プログラミング(Java・Kotlin)のお...
Java Silver SE11 まとめ記事 | プログラミング(Java・Kotlin)のお悩み解決ラボ! IT業界への転職を考えていたり、すでにIT業界で働いている人は資格の取得を考えることも多いです。   Java に関する資格で、有名なものの一つがJava Silver SE11です!  ...
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

【しう】
Java Engineer| 最近はKotlin| 「テニスとJava(プログラミング)のお悩み解決ラボ」運営者| プログラミング・開発現場の学びを主に発信|【経歴】受託系IT企業➪自社開発企業| ∮保有資格∮ : Java Silver,Oracle SQL Silver,基本情報,TOEIC 750,簿記3級

コメント

コメントする

CAPTCHA


目次