異なる鍵 A と B が存在した場合、A で暗号化したデータが B でしか復号化できず、
B で暗号化したデータが A でしか複合化できないという特殊な鍵の組み合わせを
非対称鍵 (Asymmetric Key) と言います。非対称鍵の特性を利用して
鍵の片方を暗号化用に相手に公開し (公開鍵)、もう片方を復号化用に非公開にして
おく (秘密鍵) 方式が公開鍵暗号 (Public Key Encryption) です。
公開鍵だけを知りえてもデータの復号化は事実上不可能であるため傍受や改ざんなどが
行いにくくなりますが、公開鍵だけでは悪意のある中継者による鍵のすり替えに対処
できません。公開鍵暗号を完全にするには公開鍵証明書や
電子署名と組み合わせて
PKI
を構成する必要があります。
また現実的な問題として公開鍵を用いた暗号は共通鍵暗号
と比べて非常に負荷が高いため、SSL などではセッションの最初に共通鍵を受け渡すため
だけに使用して、それ以降の通信は共有鍵暗号で行う方法を採っています。
広く使われている公開鍵アルゴリズムは RSA と DSA ですが DSA は電子署名用の
アルゴリズムですので暗号化には使用できません。また J2SE 5.0 までは RSA の
デフォルトの強度が 128bit に制限されていましたが JSE 6 で解除されました。
| RSA |
Rivest Shamir Adleman: 1978 年に開発者の頭文字から名づけられた
公開鍵暗号方式。歴史が長く実効的な鍵の発見方法も見つかっていないため
広く使用されている。RSA Data Security 社が保有していた特許が 2000 年に
切れてからさらに普及が進んでいます。
|
| DSA |
Digital Signature Algorithm: 1991 年に米国家安全保障局で開発、
1994 年に米標準技術局で認可された電子署名のための公開鍵アルゴリズム。
内部で SHA-1 を使用しているため今後強度的な拡張が加えられる予定です。
より短い鍵で強い強度を持つ ECDSA の方が良い。
|
公開鍵と秘密鍵のセット (キーペア) は
KeyPairGenerator
を使用して作成することができます。キー生成に使用できるアルゴリズムは
KeyPairGenerator
アルゴリズム、セキュア乱数のアルゴリズムは
SecureRandom アルゴリズムを参照してください。
SecureRandom のシードにパスワードに基づくハッシュ値などを指定することで
同一のキーを何度でも生成することができます。
Java
// キーペアの生成
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
generator.initialize(1024, random);
KeyPair keyPair = generator.generateKeyPair();
// 秘密鍵・公開鍵の取得
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic()
それぞれの鍵から
getEncoded()
で取得できるバイト配列を保存しておくことで次回以降の実行でも同じ鍵を
復元する事ができます (これは汎用的なフォーマットであるため多言語
からの利用も可能です)。
// 秘密鍵の保存 (公開鍵も同じ)
byte[] binary = privateKey.getEncoded();
FileOutputStream out = new FileOutputStream();
out.write(binary);
out.close();
復元時はそれぞれのフォーマットに対応する
EncodedKeySpec
を使用します。
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
// 公開鍵の復元
byte[] binary = ...; // 保存した公開鍵のバイナリ
EncodedKeySpec keySpec = new X509EncodedKeySpec(binary);
Publickey publicKey = keyFactory.generatePublic(keySpec);
// 秘密鍵の復元
binary = ...; // 保存した秘密鍵のバイナリ
keySpec = new PKCS8EncodedKeySpec(binary);
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
公開鍵を使用した暗号化/復号化は共通鍵の場合とほとんど同じです。
Cipherアルゴリズム
から公開鍵方式に対応するアルゴリズムを選択し、暗号化に公開鍵を、復号化に秘密鍵を
指定してください。
Java
// 暗号化の実行
binary = "hello, world".getBytes();
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encrypted = cipher.doFinal(binary);
// 複合化の実行
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] binary = cipher.doFinal(encrypted);