Domanda:
Qual è il modo standard per crittografare un file con una chiave pubblica in Java?
Jean-Philippe Pellet
2011-01-04 20:35:05 UTC
view on stackexchange narkive permalink

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 rimandarlo al server?

Da siti web come questo, deduco che di solito una chiave simmetrica sia generato 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 di file standard (senza librerie aggiuntive) per impacchettare la chiave simmetrica crittografata e il file crittografato simmetricamente?

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

BouncyCastle forse? È l'unica libreria che conosco che utilizza la crittografia
Come lo farei con BouncyCastle?
Qual è il tuo obiettivo di fondo e il tuo modello di minaccia? Per esempio. vuoi anche autenticare la provenienza dei dati o sei vulnerabile a un attacco MITM? Hai considerato SSL e quindi crittografando il file sul lato server, se lo desideri?
+1 ad @nealmcb, non si dovrebbe presumere che la crittografia dei file sia necessariamente la strada da percorrere.
L'app client salva i registri delle attività dell'utente il cui contenuto deve essere pubblicato su un server inalterato, anche se l'utente ha accesso in lettura / scrittura ai file salvati. Inoltre, l'utente non dovrebbe essere in grado di ispezionare i contenuti (i file sono rapporti di esercizi, progressi e errori da un'applicazione di quiz).
@JPP, ah vedi - tutta questa roba di crittografia dei file non ti aiuterà ora.
@Avid, Non capisco come la crittografia non mi aiuti - sembra fare quello che voglio. Salvare i file crittografati con la mia chiave pubblica RSA (il client non può decrittografarli indietro) e inviarli al mio server quando arriva il momento. Se il client altera il file, è immediatamente non valido perché non posso più decrittografarlo, che è esattamente quello che voglio. Dov'è il trucco?
Quattro risposte:
nealmcb
2011-01-04 22:03:43 UTC
view on stackexchange narkive permalink

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

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

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

D.W.
2011-01-07 11:22:17 UTC
view on stackexchange narkive permalink

Il modo più semplice e sicuro per crittografare i file è sborsare e invocare gpg o pgp per crittografarli. So che sembra poco elegante, ma nella mia esperienza nel rivedere un sacco di codice crittografico, questo è il modo più semplice per garantire che la tua soluzione sia sicura, senza dover sapere molto sulla crittografia. Se vuoi farlo da solo, avrai bisogno di saperne di più su come funziona la crittografia e aumenta il rischio di un problema di sicurezza.

Assicurati che ci sia protezione dell'autenticità per i dati crittografati (ad esempio, crittografare e quindi firma / MAC): avrai bisogno sia della protezione della riservatezza che dell'autenticità. Un errore molto comune è crittografare 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 io 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, oppure puoi crederci sulla parola. Ehi, la crittografia è roba complicata; 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. Anche l'approccio di paglia che citi nella tua domanda soffre di questo difetto e sembra che anche alcune delle risposte proposte qui abbiano un difetto simile.

Un approccio alternativo, che è molto buono se il cliente e server sono connessi in tempo reale, è quello di aprire un canale crittografato TLS tra il client e il server e inviare i dati su quel canale. Assicurati che il client verifichi la chiave pubblica / certificato del server. Se desideri autenticare i client, fornisci ai client un certificato client e assicurati che il server richieda al client di fornire un certificato client e convalidi tale certificato.

1. Aggiunge il requisito che lo strumento gpg / pgp sia installato sulla casella del client. 2. Ora hai un nuovo problema: devi garantire l'integrità di uno strumento che stai chiamando tramite exec ().
@Graham, sì, richiede gpg / pgp. No, questo non è un problema nuovo: devi già garantire l'integrità del tuo codice, quindi usa lo stesso identico meccanismo per gpg / pgp. In pratica l'integrità non è difficile. Nota: non ho detto che la mia soluzione non ha inconvenienti, ho detto che era il modo più semplice per ottenere una buona sicurezza. Se hai un modo più semplice per farlo in modo sicuro, sentiti libero di pubblicarlo. Ma tieni presente in anticipo che ci sono molti dettagli complicati.
@D.W. ma hai una condizione di gara. `if (pgpExecutable.isValid ()) {exec (pgpExecutable.path (), ...)`
@Graham, ti sbagli semplicemente. Questa non è la soluzione che stavo proponendo, né la mia soluzione ha una condizione di gara o qualsiasi altro problema simile. Sembra che tu sia un po 'confuso sul modello di minaccia e su come il software viene distribuito sulle macchine finali.
Sì: ha quello che ho dimostrato nel mio commento.
@Graham, di nuovo, ti sbagli. Come ho già detto, stai attaccando un uomo di paglia. Non sto proponendo quello che pensi io proponga.
@D.W. in tal caso, specifica la tua risposta. Sembra proprio che tu lo sia, e sono sicuro che la maggior parte dei lettori troverà "esempio specifico di un problema" / "ti sbagli e non posso essere disturbato a spiegare perché" noioso dopo un paio di giri;)
@Graham, Sì, sono d'accordo che se lo strumento pgp utilizzato dal programma Java è compromesso, allora abbiamo un problema. Tuttavia (e penso che @D.W. Sarà d'accordo con me), questo non è un "nuovo problema", rispetto a fare una crittografia funzionalmente equivalente "internamente" in Java per evitare dipendenze. Qualsiasi cracker in grado di corrompere lo strumento pgp può altrettanto facilmente danneggiare il codice funzionalmente equivalente nell'applicazione Java.
@David Cary, sì, sono d'accordo. (Per approfondire la mia precedente affermazione: "devi già garantire l'integrità del tuo codice [Java], quindi usa lo stesso identico meccanismo per [garantire l'integrità di] gpg / pgp".) Oh beh, questo è uno degli svantaggi del formato Stack Exchange su argomenti come la crittografia; i voti positivi non sono sempre correlati alla migliore consulenza tecnica.
AviD
2011-01-09 06:30:16 UTC
view on stackexchange narkive permalink

@JPP, questo tuo commento mi fa pensare che tu stia facendo la domanda sbagliata:

L'app client salva i registri delle attività degli utenti il ​​cui contenuto dovrebbe essere pubblicato su un server inalterato, anche se l'utente ha accesso in lettura / scrittura ai file salvati. Inoltre, l'utente non dovrebbe essere in grado di ispezionare i contenuti (i file sono rapporti di esercizi, progressi e errori da un'applicazione di quiz).

Se l'app client scrive i file di registro e li crittografa, significa che l'app client ha accesso alla chiave di crittografia, qualunque essa sia.
Tuttavia, stai provando per impedire all'utente dell'app client di leggere i file!
Non funzionerà, perché:

  1. L'utente ha accesso a tutto ciò a cui l'app client ha accesso, incluso il il contenuto del file e la chiave di crittografia ...
  2. L'utente ha il controllo di qualsiasi cosa in esecuzione nel proprio processo, ovvero può anche allegare un debugger all'app client, quindi non preoccuparti di cercare di diventare intelligente e trovare un modo per offuscare la chiave di crittografia.

Per me, il tuo problema suona più come un problema di controllo dell'accesso: come posso scrivere un file di registro da un'app client, senza che l'utente abbia accesso ai contenuti?
Un modo sarebbe costruire un servizio locale (es. servizio Windows, su Windows) che gira in un contesto utente diverso; l'app client parlerebbe al servizio e il servizio scriverà i contenuti 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 nel file nessuno dei contenuti.

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 Windows locale.

Non vedo il problema se utilizzo il mio certificato pubblico per crittografare ciò che il client scrive su disco e quindi utilizzo la mia chiave privata per decrittografarlo una volta ricevuto.
@JPP, anche supponendo che la chiave privata non sia disponibile sulla macchina client, ma piuttosto solo sul server, nota anche il punto n. 2 sopra, ad es. allegare un debugger: se l'utente malintenzionato è determinato a sovvertire il processo, sarà in grado di farlo. Questo non vuol dire che la crittografia con la chiave pubblica autonoma non aggiungerà valore - * fa * alza un po 'il livello, ma solo fintanto che ti rendi conto che è TUTTO quello che fa, e può essere aggirato.
Grazie per la spiegazione. Certo, è possibile collegare un debugger e modificare direttamente l'array di byte prima che sia crittografato. Ma qual è l'alternativa? Eliminare tutti i dati dell'utente generati in questo modo se non è in grado di comunicare con il server in questo momento? E anche allora: posso anche collegare il debugger e modificare l'array di byte prima che il client lo invii al server, o prima che venga inviato a un servizio Windows protetto, quindi la situazione non è migliore. O mi sta sfuggendo qualcosa?
No, ad @JPP, non manca qualcosa - tranne per il fatto fondamentale che * non puoi fare affidamento sul client *. Nel complesso, e dati i vincoli, la crittografia così come l'hai impostata è probabilmente la migliore, ma prendila per quello che vale. Impedirà la manomissione del file, ma durante l'elaborazione è tutto aperto. Se questo è un problema, sarebbe meglio riprogettare il sistema in modo che l'elaborazione sensibile venga eseguita sul server.
Jean-Philippe Pellet
2011-01-04 23:35:16 UTC
view on stackexchange narkive permalink

A quanto pare, non c'è modo di farlo con la libreria standard senza una significativa ricodifica di cose già disponibili in Bouncy Castle, per esempio.

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

  // install security providerif (Security.getProvider (BouncyCastleProvider.PROVIDER_NAME) == null) {Security .addProvider (new BouncyCastleProvider ());} // carica il certificato pubblico per signingKeyStore 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 (); // crea i dati della busta CMS; // controlla http://www.ietf.org /rfc/rfc3852.txt pagine 15-16 per i dettagli CMSEnvelopedDataGenerator envelopedDataGen = new CMSEnvelopedDataGenerator (); // specifica che la chiave simmetrica generata verrà crittografata da con questa chiave pubblicaenvelopedDataGen.addKeyTransRecipient (cert); // genera automaticamente la chiave AES, data e crittografa la chiave CMSEnvelopedData data = envelopedDataGen.genera te (new CMSProcessableFile (plainfile), CMSEnvelopedDataGenerator.AES256_CBC, 256, BouncyCastleProvider.PROVIDER_NAME); byte [] encryptedData = data.getEncoded ();  

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

  // carica chiave privataKeyStore 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 dataCMSEnvelopedDataParser envelopedDataParser = new CMSEnvelopedDataParser (new ByteArrayInputStream (encryptedData));
// aspettati esattamente un recipientCollection<? > recipients = envelopedDataParser.getRecipientInfos (). getRecipients (); if (recipients.size ()! = 1) lancia una nuova IllegalArgumentException (); // recupera destinatario e decodifica itRecipientInformation = recipientiInformation = recipienti .iterator (). next (); byte [] decryptedData = recipient.getContent (privateKey, BouncyCastleProvider.PROVIDER_NAME);  

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

Un file con tali contenuti crittografati `ciperfile.enc` può essere decifrato con openssl:` openssl cms -decrypt -in cipherfile.enc -inform DER -recip testcert.pem -inkey testkey.pem`, dove `testcert.pem` è il certificato nel keystore pubblico in formato PEM e `testkey.pem` la chiave privata corrispondente.
Sono preoccupato per il fatto che questo frammento di codice non sembra fornire l'autenticazione del messaggio / protezione dell'integrità. In tal caso, è probabile che non sia sicuro contro gli attacchi attivi e quindi non è una soluzione consigliata.
@D.W. Grazie per averlo fatto notare. Come posso ripararlo? Firmalo dopo la crittografia?
Sì, la firma dopo la crittografia fornirebbe autenticazione / integrità, se eseguita correttamente. Tuttavia questo è complicato. Il modo migliore per risolverlo è affidarsi a una soluzione esistente e ben controllata per la crittografia dei file, come PGP / GPG, o per la crittografia dei canali, come SSL / TLS.
Vedi [questo post] (http://security.stackexchange.com/questions/2202/lessons-learned-and-misconceptions-regarding-encryption-and-cryptology/2206#2206) per ulteriori spiegazioni del motivo per cui è una cattiva idea crittografare senza anche autenticare e come risolvere il problema. Vale la pena sottolineare che il codice di esempio sopra elencato sembra essere ** difettoso ** e ** non deve essere utilizzato **.


Questa domanda e risposta è stata tradotta automaticamente dalla lingua inglese. Il contenuto originale è disponibile su stackexchange, che ringraziamo per la licenza cc by-sa 2.0 con cui è distribuito.
Loading...