89

.pem ファイルに保存されている公開鍵と秘密鍵を読み取る小さなコードを書いています。次のコマンドを使用してキーを生成しています。

以下のコマンドでキーのペアを生成します。

   $openssl genrsa -out mykey.pem 2048

秘密鍵を生成するこのコマンド

$openssl pkcs8 -topk8 -inform PEM -outform PEM -in mykey.pem \
    -out private_key.pem -nocrypt

このコマンドで公開鍵を取得します。

$ openssl rsa -in mykey.pem -pubout -outform DER -out public_key.der

秘密鍵と公開鍵をそれぞれ読み取る 2 つのメソッドを作成しました。

   public  PrivateKey getPemPrivateKey(String filename, String algorithm) throws Exception {
      File f = new File(filename);
      FileInputStream fis = new FileInputStream(f);
      DataInputStream dis = new DataInputStream(fis);
      byte[] keyBytes = new byte[(int) f.length()];
      dis.readFully(keyBytes);
      dis.close();

      String temp = new String(keyBytes);
      String privKeyPEM = temp.replace("-----BEGIN PRIVATE KEY-----\n", "");
      privKeyPEM = privKeyPEM.replace("-----END PRIVATE KEY-----", "");
      //System.out.println("Private key\n"+privKeyPEM);

      Base64 b64 = new Base64();
      byte [] decoded = b64.decode(privKeyPEM);

      PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(decoded);
      KeyFactory kf = KeyFactory.getInstance(algorithm);
      return kf.generatePrivate(spec);
      }

   public  PublicKey getPemPublicKey(String filename, String algorithm) throws Exception {
      File f = new File(filename);
      FileInputStream fis = new FileInputStream(f);
      DataInputStream dis = new DataInputStream(fis);
      byte[] keyBytes = new byte[(int) f.length()];
      dis.readFully(keyBytes);
      dis.close();

      String temp = new String(keyBytes);
      String publicKeyPEM = temp.replace("-----BEGIN PUBLIC KEY-----\n", "");
      publicKeyPEM = publicKeyPEM.replace("-----END PUBLIC KEY-----", "");


      Base64 b64 = new Base64();
      byte [] decoded = b64.decode(publicKeyPEM);

      X509EncodedKeySpec spec =
            new X509EncodedKeySpec(decoded);
      KeyFactory kf = KeyFactory.getInstance(algorithm);
      return kf.generatePublic(spec);
      }

やり方が稚拙な気がします。インターネット上でそれを行うより良い方法を見つけることができませんでした。一般的なケースを処理するために同じコードを書く最良の方法を誰かが教えてくれますか? サードパーティのライブラリは一切使用したくありません。
私は歌唱/暗号化に関する非常に基本的な知識を持っており、Java セキュリティ API をほとんど使用していません。ですから、私がどこかで意味をなしていない場合は、指摘してください。

4

10 に答える 10

9

さて、私のコードはあなたのものと似ていますが、違いはほとんどありません...

public static X509Certificate loadPublicX509(String fileName) 
        throws GeneralSecurityException {
    InputStream is = null;
    X509Certificate crt = null;
    try {
        is = fileName.getClass().getResourceAsStream("/" + fileName);
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        crt = (X509Certificate)cf.generateCertificate(is);
    } finally {
        closeSilent(is);
    }
    return crt;
}

public static PrivateKey loadPrivateKey(String fileName) 
        throws IOException, GeneralSecurityException {
    PrivateKey key = null;
    InputStream is = null;
    try {
        is = fileName.getClass().getResourceAsStream("/" + fileName);
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        StringBuilder builder = new StringBuilder();
        boolean inKey = false;
        for (String line = br.readLine(); line != null; line = br.readLine()) {
            if (!inKey) {
                if (line.startsWith("-----BEGIN ") && 
                        line.endsWith(" PRIVATE KEY-----")) {
                    inKey = true;
                }
                continue;
            }
            else {
                if (line.startsWith("-----END ") && 
                        line.endsWith(" PRIVATE KEY-----")) {
                    inKey = false;
                    break;
                }
                builder.append(line);
            }
        }
        //
        byte[] encoded = DatatypeConverter.parseBase64Binary(builder.toString());
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        key = kf.generatePrivate(keySpec);
    } finally {
        closeSilent(is);
    }
    return key;
}

public static void closeSilent(final InputStream is) {
    if (is == null) return;
    try { is.close(); } catch (Exception ign) {}
}
于 2013-01-05T22:57:36.640 に答える
3

私はあなたの秘密鍵の定義で、次のものを置き換える必要があると思います:

X509EncodedKeySpec spec = new X509EncodedKeySpec(decoded);

と:

PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(decoded);

あなたのopensslコマンドを見てください:

$openssl **pkcs8** -topk8 -inform PEM -outform PEM -in mykey.pem \ -out private_key.pem -nocrypt

そしてJava例外:

Only PCKS8 codification 
于 2015-12-02T20:34:19.293 に答える
2

Java ライブラリを使用すると、openssl によって生成された公開証明書を読み取るのがほぼ 1 行で済みます。

val certificate: X509Certificate = ByteArrayInputStream(
        publicKeyCert.toByteArray(Charsets.US_ASCII))
        .use {
            CertificateFactory.getInstance("X.509")
                    .generateCertificate(it) as X509Certificate
        }

しかし、まあ、秘密鍵の読み取りには問題がありました。

  1. 最初に開始タグと終了タグを削除する必要がありましたが、これは公開鍵を読み取るときに必要ありません。
  2. 次に、新しい行をすべて削除する必要がありました。
  3. 次に、バイト64を使用してバイトにデコードする必要がありました
  4. すると、 を制作することができましたRSAPrivateKey

これを参照してください:kotlinの最終的な解決策

于 2018-01-27T17:07:36.713 に答える