Pregunta

¿Cómo enumero y exporto una clave privada de un almacén de claves?

¿Fue útil?

Solución

Una parte del código original de Example Depot para enumerar todos los alias en un almacén de claves:

    // 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);
    }

La exportación de claves privadas surgió en los foros de Sun hace un par de meses, y u: turingcompleter presentó una clase DumpPrivateKey para coser en su aplicación.

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;
    }
}

Nota: este paquete Sun de uso, que es un " cosa mala " .
Si puede descargar código de apache commons , aquí hay una versión que se compilará sin previo aviso:

javac -classpath .:commons-codec-1.4/commons-codec-1.4.jar DumpPrivateKey.java

y dará el mismo resultado:

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;
    }
}

Puedes usarlo así:

java -classpath .:commons-codec-1.4/commons-codec-1.4.jar DumpPrivateKey $HOME/.keystore changeit tomcat

Otros consejos

Puede extraer una clave privada de un almacén de claves con Java6 y OpenSSL. Todo esto depende del hecho de que tanto Java como OpenSSL admiten almacenes de claves con formato PKCS # 12. Para hacer la extracción, primero usa keytool para convertir al formato estándar. Asegúrese de utilizar la misma contraseña para ambos archivos (contraseña de clave privada, no la contraseña del almacén de claves) o obtendrá fallas extrañas más adelante en el segundo paso.

keytool -importkeystore -srckeystore keystore.jks \
    -destkeystore intermediate.p12 -deststoretype PKCS12

Luego, use OpenSSL para hacer la extracción a PEM:

openssl pkcs12 -in intermediate.p12 -out extracted.pem -nodes

Debería poder manejar ese archivo PEM con la suficiente facilidad; es texto sin formato con una clave privada codificada sin cifrar y certificado (s) dentro (en un formato bastante obvio).

Cuando haga esto, tenga cuidado de mantener seguros los archivos creados. Contienen credenciales secretas. Nada le avisará si no los protege correctamente. El método más fácil para protegerlos es hacer todo esto en un directorio que no tenga derechos de acceso para nadie más que el usuario. Y nunca ponga su contraseña en la línea de comando o en variables de entorno; es demasiado fácil para otros usuarios.

Si no necesita hacerlo programáticamente, pero solo desea administrar sus claves, entonces he usado la herramienta gratuita KeyMan de IBM desde hace mucho tiempo. Muy bueno para exportar una clave privada a un archivo PFX (luego puede usar fácilmente OpenSSL para manipularlo, extraerlo, cambiar pwds, etc.).

https : //www.ibm.com/developerworks/mydeveloperworks/groups/service/html/communityview? communityUuid = 6fb00498-f6ea-4f65-bf0c-adc5bd0c5fcc

Seleccione su almacén de claves, seleccione la entrada de clave privada, luego Archivo- > Guardar en un archivo pkcs12 (* .pfx, típicamente). Luego puede ver el contenido con:

$ openssl pkcs12 -in mykeyfile.pfx -info

Aquí hay una versión más corta del código anterior, en Groovy. También tiene codificación base64 incorporada:

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-----"

Para el desarrollo de Android, para convertir el almacén de claves creado en eclipse ADT en clave pública y clave privada utilizada en SignApk.jar:

exportar clave privada:

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

edite private.rsa.pem y deje " ----- BEGIN PRIVATE KEY ----- " a " ----- FINALIZAR CLAVE PRIVADA ----- " párrafo, entonces:

openssl.exe base64 -d -in private.rsa.pem -out private.rsa.der

exportar clave pública:

keytool.exe -exportcert -keystore my-release-key.keystore -storepass <KEYSTORE_PASSWORD> -alias alias_name -file public.x509.der

firmar apk:

java -jar SignApk.jar public.x509.der private.rsa.der input.apk output.apk

Esta pregunta surgió sobre la seguridad de stackexchange, una de las sugerencias fue utilizar Keystore explorer

https: / /security.stackexchange.com/questions/3779/how-can-i-export-my-private-key-from-a-java-keytool-keystore

Después de haberlo probado, funciona muy bien y lo recomiendo encarecidamente.

En primer lugar, ¡ten cuidado! Toda su seguridad depende del & # 8230; er & # 8230; privacidad de sus claves privadas. Keytool no tiene la exportación de claves incorporada para evitar la divulgación accidental de este material sensible, por lo que es posible que desee considerar algunas salvaguardas adicionales que podrían ser poner en su lugar para proteger sus claves exportadas.

Aquí hay un código simple que le proporciona PKCS # 8 PrivateKeyInfo sin cifrar que puede utilizar OpenSSL (consulte la opción -nocrypt de su utilidad pkcs8 ):

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();
    }
  }
}

Si necesita otros formatos, puede usar un KeyFactory para obtener una especificación de clave transparente para diferentes tipos de claves. Luego puede obtener, por ejemplo, el exponente privado de una clave privada RSA y emitirlo en el formato deseado. Eso sería un buen tema para una pregunta de seguimiento.

Otra gran herramienta es KeyStore Explorer: http://keystore-explorer.sourceforge.net/

Otra forma menos convencional pero posiblemente más fácil de hacerlo es con JXplorer . Aunque esta herramienta está diseñada para explorar directorios LDAP, tiene una GUI fácil de usar para manipular almacenes de claves. Una de esas funciones en la GUI puede exportar claves privadas de un almacén de claves JKS.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top