2009-09-08 44 views
10

Estoy tratando de cifrar algunos contenidos con una clave privada RSA.Encriptación con clave privada RSA en Java

estoy siguiendo este ejemplo: http://www.junkheap.net/content/public_key_encryption_java

pero la conversión a utilizar claves privadas en lugar de público. Siguiendo ese ejemplo, creo que lo que tengo que hacer es:

  • Leer en una DER-formato de la clave
  • privada Generar un PCKS8EncodedKeySpec
  • generatePrivate llamada() desde KeyFactory para obtener un objeto clave privada
  • utilizar ese objeto clave privada con el objeto de cifrado para realizar el cifrado

Por lo tanto, los pasos:

la clave se generó aquí para allá m openssl con:

openssl genrsa -aes256 -out private.pem 2048

y luego se convirtió en formato DER con:

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

genero la PKCS8EncodedKeySpec con:

byte[] encodedKey = new byte[(int)inputKeyFile.length()]; 

try { 
    new FileInputStream(inputKeyFile).read(encodedKey); 
} catch (FileNotFoundException e) { 
    // TODO Auto-generated catch block 
    e.printStackTrace(); 
} catch (IOException e) { 
    // TODO Auto-generated catch block 
    e.printStackTrace(); 
} 

PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encodedKey); 
return privateKeySpec; 

y luego generar la clave privada Objeto con:

PrivateKey pk = null; 

try { 
    KeyFactory kf = KeyFactory.getInstance(RSA_METHOD); 
    pk = kf.generatePrivate(privateKeySpec); 
} catch (NoSuchAlgorithmException e) { 
    // TODO Auto-generated catch block 
    e.printStackTrace(); 
} catch (InvalidKeySpecException e) { 
    // TODO Auto-generated catch block 
    e.printStackTrace(); 
} 
return pk; 

Sin embargo, en la llamada a:

pk = kf.generatePrivate(privateKeySpec); 

me sale:

java.security.spec.InvalidKeySpecException: Unknown key spec. 
at com.sun.net.ssl.internal.ssl.JS_KeyFactory.engineGeneratePrivate(DashoA12275) 
at com.sun.net.ssl.internal.ssl.JSA_RSAKeyFactory.engineGeneratePrivate(DashoA12275) 
at java.security.KeyFactory.generatePrivate(KeyFactory.java:237) 

Preguntas:

  • es el enfoque general ¿verdad?
  • ¿Es PCKS8EncodedKeySpec la especificación de teclas correcta para usar?
  • ¿Alguna idea sobre el error de especificación de clave no válida?
+0

Fui a través de éste y los generados con Java: http://stackoverflow.com/questions/19640735/load-public-key-data-from -file – Hayro

Respuesta

6

En primer lugar, estoy confundido por qué usted está planeando utilizar un Cipher para cifrar con una clave privada, en lugar de la firma con un Signature. No estoy seguro de que todos los proveedores de RSA Cipher usarán el tipo de bloque correcto para la configuración, pero vale la pena intentarlo.

Sin embargo, dejando de lado eso, creo que está intentando cargar una clave de formato OpenSSL no estándar. Convertirlo a DER con rsa es esencialmente solo una decodificación de base 64; la estructura de la clave no es PKCS # 8.

lugar, después de genrsa, utilice el comando openssl pkcs8 para convertir la clave generada a PKCS # 8 sin cifrar, formato DER:

openssl pkcs8 -topk8 -nocrypt -in private.pem -outform der -out private.der 

Esto producirá una clave privada sin cifrar que se puede cargar con un PKCS8EncodedKeySpec.

+0

Honestamente, no estaba al tanto de Signature. Para asegurarme de que entiendo su uso, ¿Inicializaría el objeto de firma, llamaría la actualización con los bytes que quiero firmar y luego llamaría a la señal? ¿Y luego puedo almacenar los bytes devueltos desde el signo como mi firma digital? – wadesworld

+0

Sí, ese es el uso correcto. – erickson

+0

Hola. ¿Alguien finalmente resolvió el problema? Tengo una clave privada que no puedo cargar en Java para continuar con la fase de firma. Mi privateKey es RSA, PKCS # 8 DER y tiene una contraseña. ¿Cómo puedo cargar eso en Java? La excepción en mi caso es 'java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: entrada DER, error de la etiqueta entera ' – BRabbit27

10

No puede encriptar con clave privada. Si JCE te permite hacer eso, es solo por accidente.

Tiene que firmar. Aquí está el fragmento de código para hacer eso,

signer = Signature.getInstance("SHA1withRSA"); 
signer.initSign(privateKey); // PKCS#8 is preferred 
signer.update(dataToSign); 
byte[] signature = signer.sign(); 
+1

's/public/private /' en su primera línea. – caf

+0

Perfecto - muchas gracias! – wadesworld

4

No es un accidente que se permita el cifrado con clave privada. Si desea dividir una firma en hash y cifrado individual, entonces el cifrado con clave privada es esencial. Digamos que tengo un documento que debo firmar y mi clave reside en un HSM de red. Ahora bien, transmito todo el documento al HSM para firmar o puedo crear un hash local y transmitirlo al HSM solo para el cifrado. Mi elección dependerá de si el cálculo del hash local me da un mejor rendimiento, es decir, un cómputo hash delegado con latencia de la red.

2

Esta pregunta es bastante antigua, pero recientemente descubrí el problema (estoy implementando requisitos de algún protocolo que requiere cifrado con clave privada). Me limitaré a citar el post de forum:

Recientemente me encontré en el mismo tema, presentaron PMR 22265,49R y soporte de IBM después de consultar con el "desarrollo" (el que esas son) dictaminó que las claves privadas no se pueden utilizar para cifrado. No importa cuánto haya intentado discutir con ellos que las claves privadas no deberían usarse para la protección de datos, que es solo un propósito detrás del cifrado, y que está perfectamente bien usar claves privadas para el cifrado para lograr el no repudio, eran inquebrantables en su creencia. Tienes que amar a las personas, que insisten en que 2x2 = 5.

Así es como trabajé en torno a este problema: Básicamente, creé un objeto de clave pública con material criptográfico de clave privada. Tendrá que hacer lo contrario, crear un objeto de clave privada con material criptográfico de clave pública, para descifrarlo con clave pública si desea evitar la excepción "La clave pública no se puede usar para descifrar".

RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey) ks.getKey(keyAlias, ksPassword.trim().toCharArray()); 
RSAPublicKeySpec spec = new RSAPublicKeySpec(
    privateKey.getModulus(), 
    privateKey.getPrivateExponent() 
); 
Key fakePublicKey = KeyFactory.getInstance("RSA").generatePublic(spec); 
encryptCipher.init(Cipher.ENCRYPT_MODE, fakePublicKey); 
+1

Eso es muy arriesgado si trata el exponente de clave privada como el exponente público y lo distribuye, porque dada la clave privada (que llama la "clave pública") es fácil derivar la clave pública real (que ahora es llamando a la "clave privada"). No dejes que esa "clave pública" salga en público, o tu sistema se verá comprometido. Puede ser tan simple como adivinar que el exponente de la "clave privada" es 65537. –

+0

Estaba buscando esto por tanto tiempo. Estoy muy agradecido por esta respuesta. El nombre "clave privada y pública" es totalmente erróneo en este caso de uso, pero hay situaciones en las que esto es relevante. –

+0

@JimFlood Si entiendo correctamente, y mi situación es similar, dmitry creó un 'RSAPublicKeySpec' para contener los datos de la clave privada. Obviamente, él no va a distribuir la clave privada, solo la clave pública original que ahora se puede usar para probar (descifrar) que la clave privada fue para cifrado, es decir, no repudio. – Guss

0

intente esto:

java.security.Security.addProvider(
        new org.bouncycastle.jce.provider.BouncyCastleProvider() 
      ); 
Cuestiones relacionadas