Rhythm & Biology

Engineering, Science, et al.

AES128暗号化 - Java編 -

先日iPhone(というかObjective-C)でのAES128暗号化について触れましたが、今回はJava編です。未確認ですが、おそらくAndroidでも動きます。

/*
 *  $ javac CryptAES.java
 *  $ java CryptAES <secret_key> <iv> <message>
 */
import java.security.spec.AlgorithmParameterSpec;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;

class CryptAES {
  static final String cipher_type = "AES/CBC/PKCS5Padding";

  public static void main(String[] args) {
    String key  = args[0];
    String iv   = args[1];
    String data = args[2];

    byte[] enc = encode(key, iv, data.getBytes());
    byte[] dec = decode(key, iv, enc);

    for (int i = 0; i < enc.length; i++) {
      System.out.printf("%02x", enc[i]);
    }
    System.out.println();
        
    System.out.println(new String(dec));
  }

  public static byte[] encode(String skey, String iv, byte[] data) {
    return process(Cipher.ENCRYPT_MODE, skey, iv, data);
  }

  public static byte[] decode(String skey, String iv, byte[] data) {
    return process(Cipher.DECRYPT_MODE, skey, iv, data);
  }

  private static byte[] process(int mode, String skey, String iv, byte[] data) {
    SecretKeySpec key = new SecretKeySpec(skey.getBytes(), "AES");
    AlgorithmParameterSpec param = new IvParameterSpec(iv.getBytes());
    try {
      Cipher cipher = Cipher.getInstance(cipher_type);
      cipher.init(mode, key, param);
      return cipher.doFinal(data);
    } catch (Exception e) {
      System.err.println(e.getMessage());
      throw new RuntimeException(e);
    }
  }

}

今回はivは指定のものを使うようにしてありますが、特に指定がなければ自動で生成されますし、そのivをあとから取り出すことももちろん可能です。
パディング方式に関しては外部ライブラリをいれない限りはPKCS7が使えません。ただし、デフォルトで使えるPKCS5は7と互換性が(ほぼ)あるため、特に問題が起きることはないでしょう(逆にPKCS7のライブラリがバグってるという話もあるので、無理にPKCS7にしようとすると本末転倒な結果になりかねません)。
それから、128bitの指定などは特にしていないのですが、secret keyやivの長さ(どちらも16バイト)から自動で判別しているのだと思います。secret keyの長さを変えれば自動で256bitになったりするのでしょうか(要検証)。

Javaは普段使ってないので、もしマズいところがあればご指摘頂けるとありがたいです。