Qual è il modo standard per crittografare un file con una chiave pubblica in Java?

14

Sto scrivendo un'app client in Java che invia dati crittografati al server. Tutti i client hanno la mia chiave pubblica RSA. Esiste un modo standard per crittografare un determinato file con esso per inviarlo al server?

Da siti web come questo , ritengo che di solito, un simmetrico la chiave viene generata per crittografare il file effettivo e questa chiave viene quindi crittografata con la chiave pubblica RSA e inviata insieme al file. Esiste un modo standard in Java o un formato file standard (senza librerie aggiuntive) per il pacchetto della chiave simmetrica crittografata e del file simmetricamente crittografato?

Naturalmente, potrei progettare il mio formato di file, ma preferirei attenermi agli standard, se possibile.

    
posta Jean-Philippe Pellet 04.01.2011 - 15:35
fonte

4 risposte

8

Un comune formato di crittografia standard è Cryptographic Message Syntax (CMS, evoluto da PKCS # 7), e ad es. BouncyCastle lo supporta. Permette anche le firme, ed è la base, ad esempio, per la sicurezza dei messaggi di posta S / MIME. Potrebbe essere eccessivo, ma è ampiamente supportato.

Il codice di esempio è fornito da Bouncy Castle. Per CMS, vedere org.bouncycastle.cms. prova , probabilmente gli esempi di dati in busta.

Un'altra opzione è il formato XML Encryption, standardizzato da W3C. Per gli esempi Java, vedere ad es. Esplorazione di XML Encryption, Parte 1 o eseguirlo con XSS4J: Implementazione della crittografia XML in Java

    
risposta data 04.01.2011 - 17:03
fonte
3

Il modo più semplice e sicuro per la crittografia dei file è quello di eseguire lo shell out e invocare gpg o pgp per crittografarlo. So che sembra inelegante, ma nella mia esperienza di revisione di un gran numero di codici crittografici, questo è il modo più semplice per garantire che la tua soluzione sia sicura, senza dover conoscere molto sulla crittografia. Se vuoi farlo da solo, dovrai imparare di più su come funziona la crittografia e aumenta il rischio di problemi di sicurezza.

Assicurati che ci sia una protezione di autenticità per i dati crittografati (ad es., cripta e quindi firma / MAC): avrai bisogno sia della protezione della riservatezza che dell'autenticità. Un errore molto comune è criptare ma non firmare; questo errore può introdurre sottili problemi di sicurezza. (Se non sei un crittografo, mi rendo conto che potrebbe non avere alcun senso per te. Mi rendo conto che non è affatto ovvio, ma sono un crittografo. Se hai familiarità con IND-CCA2 e INT-CTXT, capirai Perchè lo raccomando, se non hai familiarità con questi concetti, puoi leggerli se vuoi, o puoi credermi sulla mia parola.Ehi, la crittografia è roba ingannevole, cosa posso dire.) Ad esempio, il sito Web a cui ti colleghi fa questo errore; Non dovrei fare affidamento su quel sito Web per consigli sulla crittografia sicura. L'approccio di paglia che hai menzionato nella tua domanda soffre anche di questo difetto, e sembra che alcune delle risposte proposte qui abbiano anche un difetto simile.

Un approccio alternativo, che è molto buono se il client e il server sono connessi in tempo reale, consiste nell'aprire un canale crittografato con TLS tra il client e il server e inviare i dati su quel canale. Assicurarsi che il client verifichi la chiave pubblica / certificato del server. Se si desidera autenticare i client, fornire ai client un certificato client e assicurarsi che il server richieda al client di fornire un certificato client e convalida tale certificato.

    
risposta data 07.01.2011 - 06:22
fonte
3

@JPP, Questo tuo commento mi fa pensare che stai ponendo la domanda sbagliata:

The client app saves user activity logs whose content should be published to a server unaltered, even if the user has read/write access to the saved files. Moreover, the user should not be able to inspect the contents (the files are exercise, progress, and error reports from a quiz application).

Se l'app client scrive i file di registro e li crittografa - ciò significa che l'app client ha accesso alla chiave di crittografia, qualunque essa sia.
Tuttavia, stai cercando di impedire all'utente di leggere l'app del client!
Non funziona, perché:

  1. L'utente ha accesso a tutto ciò a cui l'app del cliente ha accesso, inclusi il contenuto del file e la chiave di crittografia ...
  2. L'utente ha il controllo di tutto ciò che è in esecuzione nel proprio processo, ovvero può anche collegare un debugger all'app client, quindi non preoccuparsi di cercare di diventare intelligenti e capire come nascondere la chiave di crittografia.

Per me, il tuo problema assomiglia più a un controllo degli accessi - come posso scrivere un file di log da un'app client, senza che l'utente abbia accesso ai contenuti?
Un modo sarebbe quello di creare un servizio locale (ad esempio, il servizio di Windows, su Windows) che viene eseguito in un contesto utente diverso; l'app client avrebbe parlato al servizio e il servizio avrebbe quindi scritto il contenuto nel file in una posizione protetta che gli utenti normali non possono raggiungere.
Un'altra alternativa è, come @ D.W. suggerito, inviarlo direttamente al server immediatamente e non scrivere per archiviare alcun contenuto.

Il problema con entrambe queste soluzioni è come ho notato in precedenza: l'utente ha il controllo di qualsiasi cosa nel suo processo e può bloccare o modificare qualsiasi richiesta inviata al server o al servizio locale di Windows.

    
risposta data 09.01.2011 - 01:30
fonte
1

Apparentemente, non c'è modo di farlo con la libreria standard senza ricodifica significativa di materiale già disponibile in Bouncy Castle, per esempio.

Ecco cosa mi è venuto in mente. Sul lato client, crittografo un file plainfile come segue:

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

Quindi, sul server, posso decodificare questi dati come segue:

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

Si prega di lasciare commenti se mi manca qualcosa di importante o sto facendo errori qui ... Grazie!

    
risposta data 04.01.2011 - 18:35
fonte

Leggi altre domande sui tag