公開鍵暗号

2008年03月22日

公開鍵暗号

異なる鍵 A と B が存在した場合、A で暗号化したデータが B でしか復号化できず、 B で暗号化したデータが A でしか複合化できないという特殊な鍵の組み合わせを 非対称鍵 (Asymmetric Key) と言います。非対称鍵の特性を利用して 鍵の片方を暗号化用に相手に公開し (公開鍵)、もう片方を復号化用に非公開にして おく (秘密鍵) 方式が公開鍵暗号 (Public Key Encryption) です。

公開鍵暗号化

公開鍵だけを知りえてもデータの復号化は事実上不可能であるため傍受や改ざんなどが 行いにくくなりますが、公開鍵だけでは悪意のある中継者による鍵のすり替えに対処 できません。公開鍵暗号を完全にするには公開鍵証明書電子署名と組み合わせて PKIWikipedia検索 を構成する必要があります。

中継者攻撃

また現実的な問題として公開鍵を用いた暗号は共通鍵暗号 と比べて非常に負荷が高いため、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 の方が良い。

公開鍵の作成

公開鍵と秘密鍵のセット (キーペア) は KeyPairGeneratorJava™ API リファレンス を使用して作成することができます。キー生成に使用できるアルゴリズムは 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()Java™ API リファレンス で取得できるバイト配列を保存しておくことで次回以降の実行でも同じ鍵を 復元する事ができます (これは汎用的なフォーマットであるため多言語 からの利用も可能です)。

// 秘密鍵の保存 (公開鍵も同じ)
byte[] binary = privateKey.getEncoded();
FileOutputStream out = new FileOutputStream();
out.write(binary);
out.close();

復元時はそれぞれのフォーマットに対応する EncodedKeySpecJava™ API リファレンス を使用します。

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);
CVS 2008/04/01