共通鍵暗号
共通鍵暗号
共通鍵 (common key; 対称鍵) は暗号化と復号化に同じ鍵を使用する方法です。パスワードを使用した暗号化として一般に広く使用されています。
共通鍵暗号は暗号化と復号化に同じ鍵を使用しなければならないため、離れたところで暗号化を行わなければならない場合は鍵を持ち出さなければならないという運用上の弱点があります。インターネットのような信頼性の低い非専用回線ネットワークを経由してデータを受け渡しするような場合は公開鍵暗号を使用してください。
しかし公開鍵方式と比べて強度的な弱さがあるわけではなく、単に秘匿性の高いデータを平文のままファイルやデータベースに保存したくないというような場合には共通鍵の方が向いています。
共通鍵アルゴリズム
代表的な共通鍵アルゴリズムは以下の通り。Sun JSE 6 のデフォルト状態は輸入管理制限によって 128bit の制限が設けられています。大抵の状況では 128bit blowfish か AES で十分と思われますが、日本国内での利用であれば制限を解除する事でより強度の高い暗号を使用することもできます。
DES は認知度さえ高いですが既に解読が可能な状態であるため、互換性が必要な場合でもトリプル DES を使用してください。
ブロック長 | 鍵長 | ||
DES | 64bit | 56bit | Data Encyption Standard: 1970 年代から存在する暗号化方式。米国の暗号規格として長い間採用されていたため世界中で広く使われていますが、現在では専用のコンピュータで数日程度で解読できるためセキュリティが重視される状況では使用されていません。 |
トリプルDES | - | - | Triple DES (DESede): 暗号化、復号化、暗号化と DES を 3 重に施す方式。3 倍に拡張したキーの中に 3 つのサブキーが含まれる。全て同じサブキーを使用すれば DES と互換性のある暗号化/復号化を行うことができる。 |
Blowfish | 64bit | 32-448bit | アルゴリズムに特許がとられていないため完全なライセンスフリーで利用できる。デフォルトで 128bit 制限あり。 |
AES | 128bit | 128, 192, 256bit | Advanced Encryption Standard: DES に代わる暗号化アルゴリズムとして 2001 年に米国暗号規格となった暗号化方式。デフォルトで 128bit 制限あり。 |
Java で使用できるアルゴリズムはこちらを参照。
共通鍵の作成
共通鍵は数十~数百ビットの短いバイナリから生成します。パスワードなどの可変長データを鍵として使用する場合は一度 MD5 や SHA などでハッシュ化したものを使用してください。
// 共通鍵の作成
String password = "abc678iop";
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] key = md.digest(password.getBytes("UTF-8"));
SecretKey secretKey = new SecretKeySpec(key, 0, 16, "Blowfish");
システム的にキーを発生させて良いのであれば KeyGenerator
を使用します。
KeyGenerator generator = KeyGenerator.getInstance("Blowfish");
generator.init(128);
SecretKey secretKey = generator.generateKey();
// キーの保存
byte[] encoded = secretKey.getEncoded();
out.write(encoded);
// キーの復元
secretKey = new SecretKeySpec(encoded, "Blowfish");
暗号化と復号化
共通鍵方式での暗号化はアルゴリズムを指定して取得した Cipherを使用します。
// 暗号化するバイナリデータ
String clearText = "This is secret text.";
byte[] binary = clearText.getBytes("UTF-8");
// 暗号化の実行
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encrypted = cipher.doFinal(binary);
復号化は init() に渡すモードが異なるだけで暗号化とほとんど同じです。
// 復号化の実行
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] binary = cipher.doFinal(encrypted);
// 元の文字列を復元
String clearText = new String(binary, "UTF-8");