AES暗号アルゴリズムを使用してデータを暗号化する


TwitterでOAuth認証を行う(3:Access Tokenを取得する)“で取得したAccess TokenとAccess Token Secretなど
は、その情報をもっているだけでアカウントを使用できる為、情報を盗まれてアカウントを悪用されたり、
のっとられたりする恐れがあります。

このようなリスクを回避する為に、Access TokenとAccess Token Secretなどといった重要なデータは暗号化を
施して、盗まれても利用しにくいようにしておく必要があります。

2011/6/28:記事内のコードに脆弱性がある為、加筆・修正しました。

暗号化の詳細な方法は以下から。

AES暗号アルゴリズムとは

AES暗号アルゴリズムは共通鍵暗号方式の代表的な暗号化アルゴリズムで、鍵長が128ビット、192ビット、
256ビットから選ぶことができるブロック長が128ビットのブロック暗号です。
共通鍵暗号方式にはAESの他にDESがありますが、こちらはAESの下位規格で、鍵長が短くて破られやすい事から現在はあまり使用されていません。

秘密鍵の作成

暗号化の為の秘密鍵を作成します。鍵の作成にはSecretKeySpecクラスを使用します。

SecretKeySpecクラスはbyte配列から秘密鍵を作成するクラスです。このクラスのインスタンス化された
オブジェクト自身を鍵として使用する事ができます。

SecretKeySpec key = new SecretKeySpec([鍵として使用するbyte配列], "AES");

コンストラクタの第一引数には鍵として使用するbyte配列を、第二引数には暗号化アルゴリズムを指定します。

第一引数の鍵として使用するバイト配列はプログラマが任意に指定できます。
通常はファイルとしてMODE_PRIVATEで/data/data配下にローカルファイルとして保存しておき、使用する際に適時読み込みます。
こうすることで、rootを取られない限りは他のアプリから参照されることはありません。
間違ってSDなどの外部デバイスに保存してしまうと、他のアプリから見えてしまう為、注意が必要です。
ファイルI/Oについては”データを簡単に保存する方法(ファイル入出力編)“を参照して下さい。

暗号化

暗号化はCipherクラスを使用します。Cipherクラスは暗号化と復号化の機能を提供してくれるクラスです。

// AESアルゴリズムでCipherオブジェクトを作成
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
// Cipherオブジェクトに秘密鍵を設定
c.init(Cipher.ENCRYPT_MODE, key);
// 暗号化
byte[] protectedStr = c.doFinal(pStr.getBytes());
// IVをファイルとして保存
FileOutputStream out = openFileOutput("IV", MODE_PRIVATE);
out.write(c.getIV());

Cipherクラスで暗号化する手順は以下のとおりです。

  1. Cipher#getInstanceメソッドで暗号化アルゴリズムを指定してCipherクラスのオブジェクトを作成します。
    引数の暗号化アルゴリズムには“暗号化アルゴリズム/動作モード/パディング”の書式で暗号化アルゴリズムを指定します。
    単に”AES”と指定すると、ECBモードで動作します。ECBモードは同じ文章から同じ暗号が生成される為、非常に破られやすい暗号になります。
    その為、サンプルコードではCBCモードを指定しています。CBCモードは、ブロック毎に前のブロックの暗号化された結果を XOR 演算によって重ね合わせ、その結果に対して暗号化処理を行う方法です。同じ文章から違う暗号が生成される為、ECBより強固な暗号が生成されます。
    Cipher#getInstanceメソッドで指定できるアルゴリズム、動作モード、パディングの一覧はこちらを参照して下さい。
  2. Cipher#initメソッドでオプションモードにCipher.ENCRYPT_MODEを指定して秘密鍵を初期化します。
    Cipher.ENCRYPT_MODEは鍵を暗号化モードに初期化するためのモードです。
    モードには以下の種類があります。

    DECRYPT_MODE 暗号を復号化モードに初期化する
    ENCRYPT_MODE 暗号化モードに初期化する
    UNWRAP_MODE 暗号を鍵ラッピング解除モードに初期化する
    WRAP_MODE 暗号を鍵ラッピングモードに初期化
  3. Cipher#doFinalメソッドで暗号化したいデータのbyte配列を指定して暗号化されたbyte配列を得ます。
  4. IV(Initialization Vector)を保存します。
    IV(Initialization Vector)とはCBCモードで暗号化される最初のブロックの文章に対して適用する為の値です。このIVは復号化の際に使用する為、保存しておきます。
    IVの取得にはCipher#getIVメソッドを使用します。

暗号化したデータは鍵と同様にファイルとしてMODE_PRIVATEで保存しておき、使用する際に適時読み込みます。

復号化

暗号化したデータを元の状態に戻すための操作を復号化といいます。

復号化の場合もCipherクラスを使用します。

Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
// IVの読み込み
byte[] iv = null;
FileInputStream in = openFileInput("IV");
iv = new byte[in.available()];
in.read(iv);
// 読み込んだバイトを使用できる形に変換
IvParameterSpec ips = new IvParameterSpec(iv);
// 秘密鍵を複合化モードで初期化
c.init(Cipher.DECRYPT_MODE, key, ips);
// 復号化
byte[] decryptStr = c.doFinal(dStr);

復号化の手順は以下のとおりです。

  1. Cipher#getInstanceメソッドで暗号化アルゴリズムを指定してCipherクラスのオブジェクトを作成します。
  2. IVを読み込みます。
    復号化には暗号化の際に保存したIVが必要になります。サンプルではIVを保存しているファイルを読み込んでいます。
  3. IVを使用できる形に変換します。
    IVとして記録されたバイト配列は、IvParameterSpecクラスのオブジェクトとしてインスタンス化する事で、IVとして使用することができます。
  4. Cipher#initメソッドを使用して秘密鍵を初期化します。
    Cipher#initメソッド第一引数にはオプションモードを、第二引数には秘密鍵を、第三引数にはIVを指定します。
  5. Cipher#doFinalメソッドで復号化したいbyte配列を指定して複合化されたbyte配列を得ます。