「共通鍵暗号方式のAESによる暗号化と復号化」の版間の差分

提供: Java入門
移動: 案内検索
(ページの作成:「AESとは、共通鍵暗号方式の暗号アルゴリズムの1つです。AESは、Advanced Encryption Standardの略です。DESの安全性が低下していった...」)
(相違点なし)

2015年9月20日 (日) 17:12時点における版

AESとは、共通鍵暗号方式の暗号アルゴリズムの1つです。AESは、Advanced Encryption Standardの略です。DESの安全性が低下していったため、代替のために開発されました。Javaでは、いろいろな暗号アルゴリズムが利用できます。ここでは、AESを利用して暗号化、復号化を行います。

読み方

AES
えーいーえす
Advanced Exception Standard
あどばんすど えんくりぷしょん すたんだーど

概要

AES以外の暗号アルゴリズムも利用できます。使用可能な暗号アルゴリズムを調べるをご参照ください。 このプログラムは、鍵長は、128ビットです。

流れ

プログラムの流れは、以下の通りです。

  1. 鍵を生成する
  2. IV(Initial Vector, 初期ベクトル)を生成する
  3. データを暗号化する
  4. 暗号化したデータを復号化する

PKCS5Paddingなどが見つからない

ブロック暗号方式は、データサイズがブロックサイズの倍数でないと暗号化できません。そのため、ブロックサイズに合わない最後のブロックをパディングで調整する必要があります。

パディングのためのPKCS5Paddingがあるはずなのですが、NOPADDINGしか見つからず、今回は、データサイズが必ずあっている前提でコードを書いています。

AES1

データサイズは、16バイトの倍数でなければなりません。

ソースコード AES1.java

/*
 * AES1.java
 * Copyright (C) 2015 kaoru <kaoru@localhost>
 */
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.security.spec.KeySpec;
import java.security.SecureRandom;
import javax.crypto.spec.IvParameterSpec;
import java.util.Base64;
public class AES1
{
        enum MODE {
                ENCRYPT,
                DECRYPT
        };
        public static SecretKey ENCRYPT_KEY;
        public static int KEY_SIZE = 128;
        public static byte[] ENCRYPT_IV;// = "abcdefghijabcdefghij";
        public static String ALGORITHM = "AES_128/CBC/NOPADDING";
        public static String CIPHER = "AES";
        public static String char_code = "UTF-8";
 
        public static String encrypt (String plaintext) throws Exception {
                byte[] cipher_byte = crypt(plaintext.getBytes(), MODE.ENCRYPT);
                String b64 = Base64.getEncoder().encodeToString(cipher_byte);
                return b64;
        }
        public static String decrypt (String text64) throws Exception {
                byte[] cipher_byte = Base64.getDecoder().decode(text64.getBytes() );
                byte[] plain_byte = crypt(cipher_byte, MODE.DECRYPT);
                String plaintext = new String(plain_byte, char_code);
                return plaintext;
        }
        public static byte[] crypt(byte[] input, MODE mode) throws Exception {
                byte[] output;
                try {
                        byte[] key = ENCRYPT_KEY.getEncoded();
                        byte[] iv = ENCRYPT_IV;//.getBytes(char_code);
 
                        SecretKeySpec skey = new SecretKeySpec(key, CIPHER);
 
                        IvParameterSpec ivp = new IvParameterSpec(iv);
                        Cipher cipher = Cipher.getInstance(ALGORITHM);
                        int m = (mode == MODE.ENCRYPT)
                                ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
                        cipher.init(m, skey, ivp);
                        output = cipher.doFinal(input);
                } catch (Exception e) {
                        e.printStackTrace();
                        throw new Exception("Can not crypt");
                }
                return output;
        }
        public static void makeKey () throws Exception {
                try {
                        KeyGenerator keygen = KeyGenerator.getInstance(CIPHER);
                        SecureRandom random = new SecureRandom();
                        keygen.init(KEY_SIZE, random);
                        ENCRYPT_KEY = keygen.generateKey();
                } catch (Exception e) {
                        throw new Exception("Can not make key", e);
                }
        }
        public static void makeIv () throws Exception {
                SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
                ENCRYPT_IV = new byte[16];
                random.nextBytes(ENCRYPT_IV);
        }
        public static void main(String[] args) {
                String text = "HogehogeHogehoge";
                try {
                        makeKey();
                        makeIv();
                        String cipher_text = encrypt(text);
                        String plain_text = decrypt(cipher_text);
                        System.out.println(cipher_text);
                        System.out.println(plain_text);
                } catch (Exception e) {
                        e.printStackTrace();
                }
        }
}

コンパイル

javac AES1.java

実行例

$ java AES1
6TLZ+5HF/9CIbsWa/0mo6g==
HogehogeHogehoge

エラーの例

javax.crypto.IllegalBlockSizeException: Input length not multiple of 16 bytes

平文のデータが16バイトの倍数でない場合、エラーになります。

javax.crypto.IllegalBlockSizeException: Input length not multiple of 16 bytes
        at com.sun.crypto.provider.CipherCore.finalNoPadding(CipherCore.java:1016)
        at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:984)
        at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:824)
        at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:436)
        at javax.crypto.Cipher.doFinal(Cipher.java:2165)

java.security.InvalidAlgorithmParameterException: Wrong IV length: must be 16 bytes long

IV(初期ベクトルのサイズは、16バイトでなければなりません。

java.security.InvalidAlgorithmParameterException: Wrong IV length: must be 16 bytes long
        at com.sun.crypto.provider.CipherCore.init(CipherCore.java:516)
        at com.sun.crypto.provider.AESCipher.engineInit(AESCipher.java:339)
        at javax.crypto.Cipher.implInit(Cipher.java:806)
        at javax.crypto.Cipher.chooseProvider(Cipher.java:864)
        at javax.crypto.Cipher.init(Cipher.java:1396)
        at javax.crypto.Cipher.init(Cipher.java:1327)

java.security.InvalidKeyException: The key must be 128 bits

鍵長は、128ビットでない場合、エラーになります。

java.security.InvalidKeyException: The key must be 128 bits
        at com.sun.crypto.provider.AESCipher.checkKeySize(AESCipher.java:158)
        at com.sun.crypto.provider.AESCipher.engineInit(AESCipher.java:338)
        at javax.crypto.Cipher.implInit(Cipher.java:806)
        at javax.crypto.Cipher.chooseProvider(Cipher.java:864)
        at javax.crypto.Cipher.init(Cipher.java:1396)
        at javax.crypto.Cipher.init(Cipher.java:1327)

関連項目