2010-08-09 38 views
10

Este código genera un par de claves pública/privada:Java cifrado asimétrico: mejor forma de almacenar claves públicas/privadas

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

Lo que me gustaría saber es ¿cómo se suele almacenar la clave pública:

Opción 1: almacenar los bytes

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

lo que no me gusta es atar el código para implementaciones concretas tales como PKCS8EncodedKeySpec y X509EncodedKeySpec.

Opción 2: almacenar el módulo y exponente

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

La segunda opción es más fácil de implementar, pero no sé si podría ser menos eficiente.

¿Algún consejo?

Respuesta

12

En nuestras aplicaciones, almacenamos claves públicas y privadas en formato DER para que puedan ser utilizadas y manipuladas fuera de Java más fácilmente. En nuestro caso, las claves privadas no tienen contraseñas.

Convertir la clave privada a algo más fácilmente utilizable en java:

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

A continuación, se puede obtener una clave privada RSA directamente por:

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

La clave pública es similar:

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

y léelo:

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

Muchas personas almacenan entonces los almacenes de claves. Para nuestros propósitos, necesitábamos la misma clave para ser compartida a través de múltiples aplicaciones en varios idiomas diferentes, y no queríamos duplicar los archivos en el disco.

En cualquier caso, el rendimiento no debería ser una gran preocupación, porque es probable que almacene esas claves en algún tipo de Singleton o caché en lugar de regenerarlos cada vez.

+1

DER no es realmente un formato per se, solo la forma de codificar objetos ASN.1 –

+0

Para aquellos que buscan obtener 'public. der' directamente de 'id_rsa.pub' (clave pública) en lugar de' id_rsa' (clave privada) [esta respuesta proporciona una forma de hacerlo] (http://stackoverflow.com/a/18290786/813810). – Diego

1

Si quiere definir un formato para almacenar las claves, entonces elegiría un formato que se pueda desechar para que no se rompa cuando quiera cambiar el cifrado (cuando el antiguo se debilita, por ejemplo).

Así que almacenaría los bytes codificados como base64, junto con una cadena que describe el formato, "rsa" tal vez.

2

En realidad, está almacenando los bytes en ambos casos, ya sea que se dé cuenta o no. Supongo que se insinúa la respuesta correcta en la respuesta de @Brian M. Carr, que es almacenar el objeto de nivel superior en su forma más natural. En el caso de las claves públicas, las elecciones obvias son como una estructura PKCS # 1 RSAPublicKey ASN.1, con codificación DER o como una estructura X509 SubjectPublicKeyInfo ASN.1, con codificación DER. Esto último es lo que los proveedores de Sun le otorgan, que es compatible con la clase de sol X509EncodedKeySpec. De forma similar, PKCS8EncodedKeySpec admite un formato de clave privada. Ambos formatos son estándares, y son compatibles con openssl, por ejemplo.Sun tiende - tiende a :(- a soportar estándares existentes en lugar de definir los suyos.

+0

Gracias usted. Realmente útil. Marque la respuesta de @Brian M. Carr como aceptada debido a los ejemplos del código. –

Cuestiones relacionadas