キーストアから秘密鍵を一覧表示してエクスポートするにはどうすればよいですか?
9 に答える
Java6 と OpenSSL を使用してキーストアから秘密鍵を抽出できます。これはすべて、Java と OpenSSL の両方が PKCS#12 形式のキーストアをサポートしているという事実に依存しています。抽出を行うには、まず を使用keytool
して標準形式に変換します。両方のファイルに同じパスワードを使用していることを確認してください(キーストアのパスワードではなく、プライベート キーのパスワード)。
keytool -importkeystore -srckeystore keystore.jks \
-destkeystore intermediate.p12 -deststoretype PKCS12
次に、OpenSSL を使用して PEM への抽出を行います。
openssl pkcs12 -in intermediate.p12 -out extracted.pem -nodes
その PEM ファイルを十分に簡単に処理できるはずです。これは、エンコードされた暗号化されていない秘密鍵と証明書が内部に含まれるプレーンテキストです (非常に明白な形式)。
これを行うときは、作成されたファイルを安全に保つように注意してください。それらには秘密の資格情報が含まれています。それらを正しく保護できなくても、警告は表示されません。それらを保護する最も簡単な方法は、ユーザー以外のアクセス権を持たないディレクトリでこれらすべてを行うことです。また、コマンド ラインや環境変数にパスワードを入力しないでください。他のユーザーが簡単につかむことができます。
キー ストア内のすべてのエイリアスを一覧表示するための Example Depot からのコードの一部:
// Load input stream into keystore
keystore.load(is, password.toCharArray());
// List the aliases
Enumeration aliases = keystore.aliases();
for (; aliases.hasMoreElements(); ) {
String alias = (String)aliases.nextElement();
// Does alias refer to a private key?
boolean b = keystore.isKeyEntry(alias);
// Does alias refer to a trusted certificate?
b = keystore.isCertificateEntry(alias);
}
秘密鍵のエクスポートは、数か月前にSun のフォーラムで取り上げられました。u:turingcompleterは、アプリに組み込む DumpPrivateKey クラスを考え出しました。
import java.io.FileInputStream;
import java.security.Key;
import java.security.KeyStore;
import sun.misc.BASE64Encoder;
public class DumpPrivateKey {
/**
* Provides the missing functionality of keytool
* that Apache needs for SSLCertificateKeyFile.
*
* @param args <ul>
* <li> [0] Keystore filename.
* <li> [1] Keystore password.
* <li> [2] alias
* </ul>
*/
static public void main(String[] args)
throws Exception {
if(args.length < 3) {
throw new IllegalArgumentException("expected args: Keystore filename, Keystore password, alias, <key password: default same tha
n keystore");
}
final String keystoreName = args[0];
final String keystorePassword = args[1];
final String alias = args[2];
final String keyPassword = getKeyPassword(args,keystorePassword);
KeyStore ks = KeyStore.getInstance("jks");
ks.load(new FileInputStream(keystoreName), keystorePassword.toCharArray());
Key key = ks.getKey(alias, keyPassword.toCharArray());
String b64 = new BASE64Encoder().encode(key.getEncoded());
System.out.println("-----BEGIN PRIVATE KEY-----");
System.out.println(b64);
System.out.println("-----END PRIVATE KEY-----");
}
private static String getKeyPassword(final String[] args, final String keystorePassword)
{
String keyPassword = keystorePassword; // default case
if(args.length == 4) {
keyPassword = args[3];
}
return keyPassword;
}
}
注: これは「悪いこと」であるSun パッケージを使用します。apache commons code
をダウンロードできる場合は、警告なしでコンパイルされるバージョンを次に示します。
javac -classpath .:commons-codec-1.4/commons-codec-1.4.jar DumpPrivateKey.java
同じ結果が得られます。
import java.io.FileInputStream;
import java.security.Key;
import java.security.KeyStore;
//import sun.misc.BASE64Encoder;
import org.apache.commons.codec.binary.Base64;
public class DumpPrivateKey {
/**
* Provides the missing functionality of keytool
* that Apache needs for SSLCertificateKeyFile.
*
* @param args <ul>
* <li> [0] Keystore filename.
* <li> [1] Keystore password.
* <li> [2] alias
* </ul>
*/
static public void main(String[] args)
throws Exception {
if(args.length < 3) {
throw new IllegalArgumentException("expected args: Keystore filename, Keystore password, alias, <key password: default same tha
n keystore");
}
final String keystoreName = args[0];
final String keystorePassword = args[1];
final String alias = args[2];
final String keyPassword = getKeyPassword(args,keystorePassword);
KeyStore ks = KeyStore.getInstance("jks");
ks.load(new FileInputStream(keystoreName), keystorePassword.toCharArray());
Key key = ks.getKey(alias, keyPassword.toCharArray());
//String b64 = new BASE64Encoder().encode(key.getEncoded());
String b64 = new String(Base64.encodeBase64(key.getEncoded(),true));
System.out.println("-----BEGIN PRIVATE KEY-----");
System.out.println(b64);
System.out.println("-----END PRIVATE KEY-----");
}
private static String getKeyPassword(final String[] args, final String keystorePassword)
{
String keyPassword = keystorePassword; // default case
if(args.length == 4) {
keyPassword = args[3];
}
return keyPassword;
}
}
次のように使用できます。
java -classpath .:commons-codec-1.4/commons-codec-1.4.jar DumpPrivateKey $HOME/.keystore changeit tomcat
プログラムで行う必要はなく、鍵を管理したいだけなら、IBM の無料の KeyMan ツールを長い間使用してきました。秘密鍵を PFX ファイルにエクスポートするのに非常に便利です (その後、OpenSSL を使用して簡単に操作、抽出、pwds の変更などを行うことができます)。
キーストアを選択し、秘密鍵エントリを選択してから、[ファイル] -> [pkcs12 ファイル (通常は *.pfx) に保存] を選択します。その後、次の方法でコンテンツを表示できます。
$ openssl pkcs12 -in mykeyfile.pfx -info
上記のコードを Groovy で短くしたものを次に示します。base64 エンコーディングも組み込まれています。
import java.security.Key
import java.security.KeyStore
if (args.length < 3)
throw new IllegalArgumentException('Expected args: <Keystore file> <Keystore format> <Keystore password> <alias> <key password>')
def keystoreName = args[0]
def keystoreFormat = args[1]
def keystorePassword = args[2]
def alias = args[3]
def keyPassword = args[4]
def keystore = KeyStore.getInstance(keystoreFormat)
keystore.load(new FileInputStream(keystoreName), keystorePassword.toCharArray())
def key = keystore.getKey(alias, keyPassword.toCharArray())
println "-----BEGIN PRIVATE KEY-----"
println key.getEncoded().encodeBase64()
println "-----END PRIVATE KEY-----"
この質問は、stackexchange のセキュリティに関するものでした。提案の 1 つは、キーストア エクスプローラーを使用することでした。
試してみたところ、非常にうまく機能し、強くお勧めします。
Android 開発の場合、Eclipse ADT で作成されたキーストアを SignApk.jar で使用される公開鍵と秘密鍵に変換するには:
秘密鍵のエクスポート:
keytool.exe -importkeystore -srcstoretype JKS -srckeystore my-release-key.keystore -deststoretype PKCS12 -destkeystore keys.pk12.der
openssl.exe pkcs12 -in keys.pk12.der -nodes -out private.rsa.pem
private.rsa.pem を編集し、"-----BEGIN PRIVATE KEY-----" を "-----END PRIVATE KEY-----" 段落に残します。次に:
openssl.exe base64 -d -in private.rsa.pem -out private.rsa.der
公開鍵のエクスポート:
keytool.exe -exportcert -keystore my-release-key.keystore -storepass <KEYSTORE_PASSWORD> -alias alias_name -file public.x509.der
apk に署名:
java -jar SignApk.jar public.x509.der private.rsa.der input.apk output.apk
まずは気をつけて!あなたのセキュリティはすべて、あなたの秘密鍵の…いや…プライバシーにかかっています。Keytool には、この機密情報が偶発的に開示されるのを防ぐためのキー エクスポートが組み込まれていないため、エクスポートされたキーを保護するために追加の保護策を講じることを検討することをお勧めします。
以下は、OpenSSL で使用できる暗号化されていない PKCS #8 PrivateKeyInfo を提供する簡単なコードです (そのpkcs8 ユーティリティ-nocrypt
のオプションを参照してください)。
KeyStore keys = ...
char[] password = ...
Enumeration<String> aliases = keys.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
if (!keys.isKeyEntry(alias))
continue;
Key key = keys.getKey(alias, password);
if ((key instanceof PrivateKey) && "PKCS#8".equals(key.getFormat())) {
/* Most PrivateKeys use this format, but check for safety. */
try (FileOutputStream os = new FileOutputStream(alias + ".key")) {
os.write(key.getEncoded());
os.flush();
}
}
}
他の形式が必要な場合は、KeyFactory を使用して、さまざまな種類のキーの透過的なキー仕様を取得できます。次に、たとえば、RSA 秘密鍵の秘密指数を取得し、それを目的の形式で出力できます。これは、フォローアップの質問に適したトピックになります。
これを行うための、型にはまらないが間違いなく簡単な別の方法は、JXplorerを使用することです。このツールは LDAP ディレクトリを参照するように設計されていますが、キーストアを操作するための使いやすい GUI を備えています。GUI のそのような機能の 1 つは、JKS キーストアから秘密鍵をエクスポートできます。