¿Cuál es la forma estándar de cifrar un archivo con una clave pública en Java?

14

Estoy escribiendo una aplicación de cliente en Java que envía datos cifrados al servidor. Todos los clientes tienen mi clave pública RSA. ¿Existe una forma estándar de cifrar un archivo determinado para enviarlo de vuelta al servidor?

De sitios web como este , reconozco que, por lo general, una simetría. la clave se genera para cifrar el archivo real, y esta clave luego se cifra con la clave pública RSA y se envía junto con el archivo. ¿Existe una forma estándar en Java o un formato de archivo estándar (sin bibliotecas adicionales) para empaquetar la clave simétrica cifrada y el archivo cifrado simétricamente?

Por supuesto, podría diseñar mi propio formato de archivo, pero prefiero cumplir con los estándares si es posible.

    
pregunta Jean-Philippe Pellet 04.01.2011 - 15:35
fuente

4 respuestas

8

Un formato de cifrado estándar común es la sintaxis criptográfica de mensajes (CMS, evolucionado de PKCS # 7) y, por ejemplo, BouncyCastle lo soporta. También permite firmas y es la base, por ejemplo, para la seguridad de mensajes de correo S / MIME. Puede ser una exageración, pero es ampliamente compatible.

Bouncy Castle proporciona el código de ejemplo. Para CMS, consulte org.bouncycastle.cms. prueba , probablemente los ejemplos de datos envueltos.

Otra opción es el formato de cifrado XML, estandarizado por W3C. Para ejemplos de Java, ver, por ejemplo, Explorando el cifrado XML, Parte 1 o hágalo con XSS4J: Implementando el cifrado XML en Java

    
respondido por el nealmcb 04.01.2011 - 17:03
fuente
3

La forma más simple y segura de cifrar archivos es eliminar e invocar gpg o pgp para cifrarlos. Sé que suena poco elegante, pero según mi experiencia al revisar una gran cantidad de códigos criptográficos, esta es la forma más sencilla de garantizar que su solución sea segura, sin tener que saber mucho sobre criptografía. Si desea hacerlo usted mismo, necesitará aprender más sobre cómo funciona la criptografía y el riesgo de un problema de seguridad aumenta.

Asegúrese de que haya protección de autenticidad para los datos cifrados (por ejemplo, cifrar y luego firmar / MAC): necesitará protección de confidencialidad y autenticidad. Un error muy común es cifrar pero no firmar; este error puede introducir problemas de seguridad sutiles. (Si no es un criptógrafo, me doy cuenta de que esto puede no tener ningún sentido para usted. Me doy cuenta de que esto no es en absoluto obvio, pero soy un criptógrafo. Si está familiarizado con IND-CCA2 e INT-CTXT, comprenderá ¿Por qué lo recomiendo? Si no está familiarizado con esos conceptos, puede leer sobre ellos si lo desea, o puede confiar en mi palabra. Oye, crypto es algo delicado; ¿qué puedo decir?) Por ejemplo, el sitio web al que se vincula comete este error; No debería confiar en ese sitio web para obtener consejos sobre el cifrado seguro. El enfoque del hombre de la paja que mencionas en tu pregunta también sufre este defecto, y parece que algunas de las respuestas propuestas aquí también tienen una deficiencia similar.

Un enfoque alternativo, que es muy bueno si el cliente y el servidor están conectados en tiempo real, es abrir un canal cifrado TLS entre el cliente y el servidor y enviar los datos a través de ese canal. Asegúrese de que el cliente verifique la clave pública / certificado del servidor. Si desea autenticar a los clientes, déles a los clientes un certificado de cliente y asegúrese de que el servidor requiera que el cliente proporcione un certificado de cliente y valide ese certificado.

    
respondido por el D.W. 07.01.2011 - 06:22
fuente
3

@JPP, este comentario tuyo me hace pensar que estás haciendo la pregunta incorrecta:

  

La aplicación cliente guarda los registros de actividad del usuario cuyo contenido debe publicarse en un servidor sin alteraciones, incluso si el usuario tiene acceso de lectura / escritura a los archivos guardados. Además, el usuario no debe poder inspeccionar los contenidos (los archivos son informes de ejercicios, progreso y errores de una aplicación de prueba).

Si la aplicación cliente escribe los archivos de registro y los cifra, eso significa que la aplicación cliente tiene acceso a la clave de cifrado, sea lo que sea.
Sin embargo, está intentando evitar que el usuario de la aplicación cliente lea los archivos.
Eso simplemente no va a funcionar, porque:

  1. El usuario tiene acceso a cualquier cosa a la que la aplicación cliente tenga acceso, incluido el contenido del archivo y la clave de cifrado ...
  2. El usuario tiene el control de cualquier cosa que se ejecute en su propio proceso, es decir, incluso puede adjuntar un depurador a la aplicación cliente, por lo que no se moleste en intentar ser inteligente y buscar una manera de ofuscar la clave de cifrado.

Para mí, su problema suena más como uno de control de acceso: ¿cómo puedo escribir un archivo de registro desde una aplicación cliente, sin que el usuario tenga acceso a los contenidos?
Una forma sería construir un servicio local (por ejemplo, Servicio de Windows, en Windows) que se ejecute en un contexto de usuario diferente; la aplicación cliente hablaría con el servicio, y el servicio escribiría el contenido en el archivo en una ubicación protegida que los usuarios normales no pueden alcanzar.
Otra alternativa es, como @D.W. sugerido, envíelo directamente al servidor inmediatamente y no escriba para archivar ninguno de los contenidos.

El problema con ambas soluciones, es como señalé anteriormente: el usuario tiene control sobre cualquier cosa en su proceso y puede bloquear o modificar cualquier solicitud enviada, ya sea al servidor o al servicio local de Windows.

    
respondido por el AviD 09.01.2011 - 01:30
fuente
1

Aparentemente, no hay forma de hacerlo con la biblioteca estándar sin una grabación significativa de cosas ya disponibles en Bouncy Castle, por ejemplo.

Esto es lo que se me ocurrió. En el lado del cliente, cifro un archivo plainfile de la siguiente manera:

// install security provider
if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
    Security.addProvider(new BouncyCastleProvider());
}

// load public certificate for signing
KeyStore publicKs = KeyStore.getInstance(KeyStore.getDefaultType());
publicKs.load(new FileInputStream("/path/to/publicKeystore.ks"), null);
TrustedCertificateEntry entry = (TrustedCertificateEntry) publicKs.getEntry("public", null);
X509Certificate cert = (X509Certificate) entry.getTrustedCertificate();

// create CMS envelope data;
// check http://www.ietf.org/rfc/rfc3852.txt pages 15-16 for details
CMSEnvelopedDataGenerator envelopedDataGen = new CMSEnvelopedDataGenerator();

// specify that generated symmetric key will be encrypted by with this public key
envelopedDataGen.addKeyTransRecipient(cert);

// automatically generate the AES key, encrypt the data, and encrypt the key
CMSEnvelopedData data = envelopedDataGen.generate(new CMSProcessableFile(plainfile),
        CMSEnvelopedDataGenerator.AES256_CBC, 256, BouncyCastleProvider.PROVIDER_NAME);

byte[] encryptedData = data.getEncoded();

Luego, en el servidor, puedo descifrar estos datos de la siguiente manera:

// load private key
KeyStore privateKs = KeyStore.getInstance(KeyStore.getDefaultType());
privateKs.load(new FileInputStream("/path/to/privateKeystore.ks"), null);
PrivateKeyEntry privateKeyEntry = (PrivateKeyEntry) privateKs.getEntry("privatekey",
        new KeyStore.PasswordProtection("password".toCharArray()));
PrivateKey privateKey = privateKeyEntry.getPrivateKey();

byte[] encryptedData = ...

// parse CMS envelope data
CMSEnvelopedDataParser envelopedDataParser = new CMSEnvelopedDataParser(new ByteArrayInputStream(encryptedData));

// expect exactly one recipient
Collection<?> recipients = envelopedDataParser.getRecipientInfos().getRecipients();
if (recipients.size() != 1)
    throw new IllegalArgumentException();

// retrieve recipient and decode it
RecipientInformation recipient = (RecipientInformation) recipients.iterator().next();
byte[] decryptedData = recipient.getContent(privateKey, BouncyCastleProvider.PROVIDER_NAME);

Por favor, deje sus comentarios si me falta algo importante o si estoy cometiendo errores aquí ... ¡Gracias!

    
respondido por el Jean-Philippe Pellet 04.01.2011 - 18:35
fuente

Lea otras preguntas en las etiquetas