共通鍵暗号

共通鍵 (Common Key; 対称鍵) は暗号化と復号化に同じ鍵を使用する方法です。パスワードを使用した暗号化として一般に広く使用されています。

共通鍵暗号は暗号化と復号化に同じ鍵を使用しなければならないため、離れたところで暗号化を行わなければならない場合は鍵を持ち出さなければならないという運用上の弱点があります。インターネットのような信頼性の低い非専用回線ネットワークを経由してデータを受け渡しするような場合は公開鍵暗号を使用してください。

しかし公開鍵方式と比べて強度的な弱さがあるわけではなく、単に秘匿性の高いデータを平文のままファイルやデータベースに保存したくないというような場合には共通鍵の方が向いています。

続きを読む

ハッシュ関数


ハッシュ関数 (Hash Function) とは任意長のバイナリデータから数十〜数百ビット程度の固定長バイナリを算出する関数です。古くから CRC のようなアルゴリズム誤り検出の用途で使用されてきましたが、暗号などのセキュリティで使用されるハッシュ関数はような特徴を持ちます。

  • 同じバイナリデータに対して常に同じ値が算出される。
  • 異なるバイナリデータに対して同じ値が算出される (衝突) 確率が極めて低い。
  • 算出された値から元のバイナリデータの推測が極めて難しい。

最近ではマシンパフォーマンスの向上もあって、セキュリティの用途で使用できる強いハッシュ関数がバイナリデータの誤り検出や同一性検証 (インデックス付け) などにも使用されています。

ハッシュアルゴリズム

Java で使用できるハッシュアルゴリズムには Message Digest と SHA があります。誤り検出の用途であればツール等にも広く普及している MD5 (128bit)、セキュリティ的な用途では SHA-256 (256bit) 以上で十分と思われます (速度は大差ない)。

MD5
[128bit] Message Digest Algorithm 5: RSA と組み合わせて電子署名を行えるよう開発されたアルゴリズム。データの誤り検出からパスワードの保存まで広く使用されていますが、現在では (緊急性はないものの) いくつかの脆弱性が報告されているためセキュリティの用途では SHA を使用した方が良い。
SHA
[160,224,256,384,512bit] Secure Hash Algorithm: SHA-1 (160bit), SHA-224〜SHA-512 まで存在するアルゴリズムMD5 より攻撃に強いと言われ SSL, SSHIPSec などにも使用されている。

ハッシュ値の生成

ハッシュ値アルゴリズムを指定した MessageDigestにバイト配列を与えるだけで取得できます。

byte[] binary = "hello, world".getBytes();
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] digest = md.digest(binary);

対象のバイナリが大きい場合は update() メソッドを使用することで内容を何度かに分けて更新することができます。

InputStream in = // ...
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] buffer = new byte[1024];
while(true){
  int len = in.read(buffer);
  if(len < 0)	break;
  md.update(buffer, 0, len);
}
byte[] digest = md.digest();

DigestInputStream,DigestOutputStream クラスを使用することでストリームに入出力されるデータから透過的にハッシュ値を算出することができます。

InputStream in = // ...
MessageDigest md = MessageDigest.getInstance("SHA-256");
in = new DigestInputStream(in, md);
byte[] buffer = new byte[1024];
while(true){
  int len = in.read(buffer);
  if(len < 0)	break;
}
byte[] digest = md.digest();

アルゴリズムの確認

実行環境で使用できるハッシュアルゴリズムSecurity クラスで列挙することができます。
Java SE 6 でのデフォルトの実行結果は以下の通り。

SHA-256: 256bit
SHA-512: 512bit
SHA    : 160bit
SHA-384: 384bit
MD5    : 128bit
MD2    : 128bit

セキュリティ

セキュリティ技術

情報の秘匿
データの内容を意図した相手にしか読めないようにすること。通信データの盗聴はカード番号や個人情報の盗難、企業情報の漏洩などを引き起こし、後になりすましなどの不正行為の手がかりとなります。情報の秘匿は暗号化技術により実現されます。
情報の完全性
データの内容が意図的な改ざん、あるいは偶発的な破損を受けたときに検知できること。表示されている情報が正しいことを保障できないインフラでは契約や取引などに使用できません。電子署名を使用することで署名が行われてから情報が変更されていないことが保障されます。
身元情報の証明
相手の身元情報が信頼できること。第三者による成りすましを阻止できなければいけません。認証局 (CA) によって発行された証明書を使用して相手の身元情報を客観的に証明することができます。ただし、その身元情報を認識して意図した相手かどうかを確認する (認証) 責任はユーザにあります。
否認の防止
当事者が行為を行ったことを証明できること。いわゆる、やったやらない、言った言わないの揉め事を防止します。電子署名は文書の内容に対して承認の意思を示す捺印やサインと同じ行為であり、秘密鍵にアクセスできる人間にしか作ることができません。

TLS/SSL を始め、現在普及しているセキュリティ技術のほとんどが非対称鍵技術の上に築かれています。

公開鍵基盤

非対称鍵の応用技術が進化するにつれ「この鍵は本当に A さんのものなのか?」という鍵の身元情報を証明する方法が必要になります。

申告された身元情報が正しいと言うことを保証し、その身元情報に対する改ざん不可能な電子証明書を発行する第三者機関 (認証局; CA) を設ける事で、公開鍵に関連するセキュリティ技術を完全なものにすることができます。このような社会基盤と関連技術を公開鍵基盤 (PKI; Public-Key Infrastructure) と呼びます。

暗号強度の制限解除

デフォルトの Sun JDK 環境で使用できる暗号化アルゴリズム輸入管理制限によってキー長に制限が設けられています。実行環境で使用できるキーの最大長は以下のように調べることができます。

Set<String> algorithms = Security.getAlgorithms("Cipher");
for(String algorithm: algorithms) {
  int max = Cipher.getMaxAllowedKeyLength(algorithm);
  System.out.printf("%-22s: %dbit%n", algorithm, max);
}

Sun Java SE 6 デフォルト環境での実行結果は以下の通り。ほとんどのアルゴリズムに 128bit の制限がかけられています。

BLOWFISH              : 128bit
ARCFOUR               : 128bit
PBEWITHMD5ANDDES      : 128bit
RC2                   : 128bit
RSA                   : 2147483647bit
PBEWITHMD5ANDTRIPLEDES: 128bit
PBEWITHSHA1ANDDESEDE  : 128bit
DESEDE                : 2147483647bit
AESWRAP               : 128bit
AES                   : 128bit
DES                   : 64bit
DESEDEWRAP            : 128bit
RSA/ECB/PKCS1PADDING  : 2147483647bit
PBEWITHSHA1ANDRC2_40  : 128bit

しかし本来日本国内で使用する場合はこの制限は適用外です。Sun の ダウンロードサイトから JCE Unlimited Strength Jurisdiction Policy を入手することでこの制限を解除することができます。

ダウンロードした jce_policy-6.zip を解凍し、中に含まれている local_policy.jar と US_export_policy.jar を ${java.home}/lib/security に存在するファイルと置き換えます (中は簡単なセキュリティポリシーファイルです)。

BLOWFISH              : 2147483647bit
ARCFOUR               : 2147483647bit
PBEWITHMD5ANDDES      : 2147483647bit
RC2                   : 2147483647bit
RSA                   : 2147483647bit
PBEWITHMD5ANDTRIPLEDES: 2147483647bit
PBEWITHSHA1ANDDESEDE  : 2147483647bit
DESEDE                : 2147483647bit
AESWRAP               : 2147483647bit
AES                   : 2147483647bit
DES                   : 2147483647bit
DESEDEWRAP            : 2147483647bit
RSA/ECB/PKCS1PADDING  : 2147483647bit
PBEWITHSHA1ANDRC2_40  : 2147483647bit

コードの修正なしに暗号化強度の制限を解除することができました。なおこれは Sun のサイトからダウンロードした JDK ですので、日本向けサーバ製品などにバンドルされている JDK などは最初から解除されているかも知れません。