13

このコードは、公開鍵と秘密鍵のペアを生成します。

KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(1024);
KeyPair keypair = keyGen.genKeyPair();
PrivateKey privateKey = keypair.getPrivate();
PublicKey publicKey = keypair.getPublic();

私が知りたいのは、公開鍵を通常どのように保存するかです。

オプション 1: バイトを保存する

byte[] privateKeyBytes = privateKey.getEncoded();
byte[] publicKeyBytes = publicKey.getEncoded();
// ... write to file

// convert bytes back to public/private keys
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);

EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes);
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);

私が嫌いなのは、コードをPKCS8EncodedKeySpecやなどの具体的な実装に結びつけることですX509EncodedKeySpec

オプション 2: モジュラスと指数を保存する

KeyFactory fact = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pub = fact.getKeySpec(publicKey, RSAPublicKeySpec.class);
RSAPrivateKeySpec priv = fact.getKeySpec(privateKey,RSAPrivateKeySpec.class);

// store modulus and exponent as BigIntegers
BigInteger modulus = pub.getModulus());
BigInteger exponent = pub.getPublicExponent());
// ... write to file

// recreate public key (the same applies to the private key)
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, exponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(keySpec);

2 番目のオプションは実装が簡単ですが、パフォーマンスが低下する可能性があるかどうかはわかりません。

アドバイスはありますか?

4

3 に答える 3

13

私たちのアプリケーションでは、公開鍵と秘密鍵を DER 形式で保存して、Java の外部でより簡単に使用および操作できるようにします。私たちの場合、秘密鍵にはパスワードがありません。

秘密鍵を Java でより使いやすいものに変換するには:

openssl pkcs8 -topk8 -nocrypt -in key.pem -inform PEM -out key.der -outform DER

次に、次の方法で RSA 秘密鍵を直接取得できます。

public static RSAPrivateKey getPrivateKey(File privateKeyFile) throws IOException, GeneralSecurityException {
    byte[] keyBytes = new byte[(int)privateKeyFile.length()];
    FileInputStream fis = new FileInputStream(privateKeyFile);
    fis.read(keyBytes);
    PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    RSAPrivateKey privKey = (RSAPrivateKey) keyFactory.generatePrivate(spec);
    return privKey;
}

公開鍵も同様です。

openssl rsa -in private.pem -pubout -outform DER -out public.der

そしてそれを読むには:

public static RSAPublicKey getPublicKey(File publicKeyFile) throws IOException, GeneralSecurityException {
    byte[] keyBytes = new byte[(int)publicKeyFile.length()];
    FileInputStream fis = new FileInputStream(publicKeyFile);
    fis.read(keyBytes);
    X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(keyBytes);
    KeyFactory factory = KeyFactory.getInstance("RSA");
    RSAPublicKey pubKey = (RSAPublicKey)factory.generatePublic(publicKeySpec);
    return pubKey;
}

多くの人は、次にキーストアを保存します。私たちの目的のために、いくつかの異なる言語の複数のアプリケーションで同じキーを共有する必要があり、ディスク上でファイルを複製したくありませんでした。

いずれの場合も、毎回再生成するのではなく、何らかのシングルトンまたはキャッシュにこれらのキーを格納する可能性が高いため、パフォーマンスは大きな問題にはなりません。

于 2010-08-09T15:38:47.723 に答える
2

あなたがそれを認識しているかどうかにかかわらず、実際には両方のケースでバイトを保存しています。正解は@Brian M. Carrの回答で示唆されていると思います。これは、高レベルのオブジェクトを最も自然な形式で保存することです。公開鍵の場合、明らかな選択肢は、DER エンコードされた PKCS#1 RSAPublicKey ASN.1 構造として、または DER エンコードされた X509 SubjectPublicKeyInfo ASN.1 構造としてです。後者は、Sun クラス X509EncodedKeySpec がサポートする、Sun プロバイダーが提供するものです。同様に、PKCS8EncodedKeySpec は秘密鍵形式をサポートしています。これらの形式は両方とも標準であり、たとえば openssl でサポートされています。Sun は、独自の標準を定義するよりも、既存の標準をサポートする傾向があります。

于 2010-08-09T21:52:08.293 に答える
1

キーを保存するためのフォーマットを定義したい場合は、暗号化を変更したいときに壊れないように、消耗可能なフォーマットを選択します(たとえば、古いものが弱くなった場合)。

したがって、base64 としてエンコードされたバイトを、おそらく "rsa" という形式を表す文字列と共に保存します。

于 2010-08-09T15:30:12.450 に答える