2009-09-17 11 views
16

Ho letto i seguenti thread e hanno aiutato un po ', ma sto cercando un po' più di informazioni.Come implementare la crittografia AES 256-bit Java con CBC

How to write AES/CBC/PKCS5Padding encryption and decryption with Initialization Vector Parameter for BlackBerry

Java 256bit AES Encryption

In sostanza, quello che sto facendo sta scrivendo un programma che crittografare una richiesta da inviare su TCP/IP, e poi decifrati da un programma server. La crittografia dovrà essere AES, e facendo alcune ricerche ho scoperto che ho bisogno di usare CBC e PKCS5Padding. Quindi in pratica ho bisogno di una chiave segreta e anche di una IV.

L'applicazione che sto sviluppando è per un telefono, quindi voglio usare i pacchetti di sicurezza java per mantenere la dimensione bassa. Ho fatto il disegno, ma non sono sicuro dell'implementazione della IV e della chiave condivisa.

Ecco po 'di codice:

// My user name 
byte[] loginId = "login".getBytes(); 

byte[] preSharedKey128 = "ACME-1234AC".getBytes(); 
byte[] preSharedKey192 = "ACME-1234ACME-1234A".getBytes(); 
// 256 bit key 
byte[] preSharedKey256 = "ACME-1234ACME-1234ACME-1234".getBytes(); 
byte[] preSharedKey = preSharedKey256; 

// Initialization Vector 
// Required for CBC 
byte[] iv ={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; 
IvParameterSpec ips = new IvParameterSpec(iv); 


byte[] encodedKey = new byte[loginId.length + preSharedKey.length]; 

System.arraycopy(loginId, 0, encodedKey, 0, loginId.length); 
System.arraycopy(preSharedKey, 0, encodedKey, loginId.length, preSharedKey.length); 

// The SecretKeySpec provides a mechanism for application-specific generation 
// of cryptography keys for consumption by the Java Crypto classes. 

// Create a key specification first, based on our key input. 
SecretKey aesKey = new SecretKeySpec(encodedKey, "AES"); 

// Create a Cipher for encrypting the data using the key we created. 
Cipher encryptCipher; 

encryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
// Initialize the Cipher with key and parameters 
encryptCipher.init(Cipher.ENCRYPT_MODE, aesKey, ips); 

// Our cleartext 
String clearString = "33,8244000,9999,411,5012022517,0.00,0,1,V330"; 
byte[] cleartext = clearString.getBytes(); 

// Encrypt the cleartext 
byte[] ciphertext = encryptCipher.doFinal(cleartext); 

// Now decrypt back again... 
// Decryption cipher 
Cipher decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
// Initialize PBE Cipher with key and parameters 
decryptCipher.init(Cipher.DECRYPT_MODE, aesKey, ips); 

// Decrypt the cleartext 
byte[] deciphertext = decryptCipher.doFinal(ciphertext); 

In poche parole quello che dovrebbe fare è crittografare qualche messaggio che può decifrato dal server senza il server necessità di ottenere una chiave o IV dal telefono. C'è un modo per farlo in modo da poter mettere al sicuro la IV e la chiave del telefono e avere ancora la chiave e la IV conosciute dal server? Sentiti libero di dirmi di rendere le cose più chiare se non lo sono.

+1

Le chiavi e le password hardcoded qui sono solo per la mia comprensione. Non so molto sulla crittografia, quindi sono fondamentalmente in modalità make-it-compile-ed-run. – Stevus

+1

Qual è il tuo modello di minaccia? Voglio dire, se stai pensando che sia necessaria la crittografia, devi avere qualche idea su chi vorrebbe queste informazioni e perché, quanto ottenerle ti farebbe male, a loro vantaggio, ecc. – erickson

+0

Suppongo che il mio modello di minaccia sia che abbiamo certe account/dati di accesso necessari per effettuare una transazione bancaria e non vogliamo che siano esposti. E 'quello che stai cercando? – Stevus

risposta

11

Ci sono alcuni problemi con il codice. Prima di tutto, dovresti davvero usare un generatore di chiavi per generare chiavi segrete. Usare semplicemente del testo potrebbe funzionare per alcuni algoritmi, ma altri hanno chiavi deboli e così via che devono essere testati.

Anche se si desidera eseguire la crittografia basata su password, la password deve essere eseguita tramite un algoritmo di derivazione chiave per produrre una chiave, come mostrato in my answer alla domanda già citata.

Inoltre, non utilizzare il metodo no-arg getBytes() di String. Questo dipende dalla piattaforma. Se tutte le stringhe che si codificano contengono solo caratteri del set di caratteri US-ASCII, chiarire specificando la codifica in modo esplicito. Altrimenti, se le piattaforme telefoniche e server utilizzano codifiche di caratteri differenti, la chiave e IV non si presenteranno allo stesso modo.

Per la modalità CBC, è meglio utilizzare una nuova IV per ogni messaggio inviato. Di solito, gli IV CBC sono generati casualmente. Altre modalità come CFB e OFB richiedono IV IV per ogni messaggio. Gli IV vengono di solito inviati con il testo cifrato — Gli IV non devono essere tenuti segreti, ma molti algoritmi si interromperanno se viene utilizzato un IV prevedibile.

Il server non ha bisogno di ottenere il segreto o IV direttamente dal telefono. È possibile può configurare il server con la chiave segreta (o password, da cui viene derivata la chiave segreta), ma in molte applicazioni, questo sarebbe un cattivo progetto.

Ad esempio, se l'applicazione verrà distribuita ai telefoni di più persone, non è consigliabile utilizzare la stessa chiave segreta. Un utente malintenzionato può recuperare la chiave e interrompere il sistema per tutti.

Un approccio migliore consiste nel generare nuove chiavi segrete al telefono e utilizzare un algoritmo di chiave d'accordo per scambiare la chiave con il server. Per questo può essere usato il contratto chiave Diffie-Hellman, oppure la chiave segreta può essere crittografata con RSA e inviata al server.


Aggiornamento:

Diffie-Hellman in modalità "effimera-statico" (e la modalità "statico-statica" troppo, anche se questo è meno desiderabile) è possibile senza un messaggio iniziale dal server al il telefono, a condizione che la chiave pubblica del server sia incorporata nell'applicazione.

La chiave pubblica del server non presenta lo stesso rischio di incorporare una chiave segreta comune nel telefono. Dal momento che è una chiave pubblica, la minaccia sarebbe un hacker che mette le mani su (o da remoto hackerando) il telefono e sostituisce la vera chiave pubblica con una chiave falsa che gli permette di impersonare il server.

La modalità statico-statica potrebbe essere utilizzata, ma in realtà è più complicata e un po 'meno sicura. Ogni telefono avrebbe bisogno della sua unica coppia di chiavi, o ricadrebbe nel problema della chiave segreta. Almeno non sarebbe necessario che il server tenga traccia di quale telefono ha quale chiave (supponendo che ci sia un meccanismo di autenticazione a livello di applicazione, come una password).

Non so quanto siano veloci i telefoni. Sul mio desktop, generare una coppia di chiavi effimera impiega circa 1/3 di secondo. Generare parametri Diffie-Hellman è molto lento; vorresti sicuramente riutilizzare i parametri dalla chiave del server.

+0

Al momento, il design che mi viene detto di usare dice che possiamo usare la stessa chiave per ogni telefono ma non sono d'accordo. L'approccio Diffie-Hellman è facile da implementare? – Stevus

+0

No, Diffie-Hellman è un po 'confuso, almeno per me. Usa la classe KeyAgreement. La crittografia RSA è più facile. Utilizza un Cipher come la crittografia AES che stai attualmente utilizzando. Una cosa da notare con RSA è che il testo cifrato sarà centinaia di byte, che è un po 'uno spreco se il testo in chiaro è solo pochi byte; non sono sicuro se ciò è importante nella tua domanda. Un'altra opzione da considerare è che se la comunicazione è costituita da messaggi molto brevi (da 100 a 200 byte) solo dal telefono al server, è possibile crittografare il messaggio stesso con RSA. – erickson

+0

Sì, penso che il livello di sicurezza che sto cercando non implichi qualcosa di veramente complicato. Lo terremo comunque a mente. – Stevus

2

Fatto progetti simili in una midlet prima, ho seguito consiglio per voi:

  1. Non v'è alcun modo sicuro per memorizzare segreto condiviso al telefono. Puoi usarlo ma questo rientra in una categoria denominata Security through Obscurity. È come un tipo di sicurezza "chiave sotto il tappeto".
  2. Non utilizzare AES 256 bit, che non è ampiamente disponibile. Potrebbe essere necessario installare un altro JCE. AES a 128 bit o TripleDES sono ancora considerati sicuri. Considerando il n. 1, non dovresti preoccuparti di questo.
  3. La crittografia utilizzando una password (diversa per ciascun utente) è molto più sicura. Ma non dovresti usare la password come la chiave che stai mostrando nell'esempio. Utilizzare PBEKeySpec (crittografia basata su password) per generare le chiavi.
  4. Se si è solo preoccupati degli attacchi MITM (man-in-the-middle), utilizzare SSL.
+0

Perché non è possibile utilizzare AES a 256 bit? Posso già creare una chiave a 256 bit nella mia configurazione di prova, ma è fatta manualmente. Principalmente, il management è preoccupato che qualcuno intercetti una trasmissione e utilizzi le informazioni nella trasmissione o ottenga un telefono e inverta l'algoritmo e fondamentalmente sia un impostore nella nostra rete. – Stevus

+0

Molti telefoni che abbiamo provato non lo supportano. AES 128 bit è ancora utilizzato dalla mia banca. È sicuro –

+1

In realtà alcuni punti deboli sono stati trovati in AES 256. AES-128 è molto potente ed è consigliato da Bruce Schneier su AES 256 quando non è richiesto per l'interoperabilità. (http://www.schneier.com/blog/archives/2009/07/another_new_aes.html) Tuttavia, l'algoritmo non importa se la chiave non è sicura. – erickson

Problemi correlati