Come parte della crittografia end-to-end per la mia app, sto seguendo la procedura standard di utilizzo di RSA per scambiare la chiave temporanea AES256. Attualmente quando A decide la chiave da inviare a B, la crittografa con la chiave pubblica di B. Tutto ciò sta prendendo parte a una connessione TLS al server. Comunque B è una specie di prendere la chiave della cieca fiducia che provenga da A. Ovviamente, non è come se qualcuno potesse mandare B alla chiave AES256. È necessario accedere prima al server prima che sia disposto a passare i messaggi ad A. Anche la chiave AES256 viene inviata solo durante l'installazione di una sessione tra A e B che B avrebbe dovuto accettare prima. Il server controllerà anche che ci sia un inizio di sessione richiesto tra X e B prima di inviare qualsiasi cosa a B e che è davvero X con cui B vuole fare una sessione. Il punto della fine alla fine è quello di impedire al server di sapere cosa succede tra A e B (anche se è il mio fisico).
Ho pensato che fare in modo che A includesse un hash firmato della chiave per B avrebbe rassicurato B che la chiave proveniva davvero da A. Tuttavia, java in Android non è in grado di crittografare l'hash firmato perché è esattamente 2048 bit ( come previsto). Ci sarebbe qualche pericolo nel trasmettere semplicemente l'hash firmato (Java RSA con SHA512) in bella vista? La mia comprensione è che gli hash sono forzati brutali che a questo punto potresti anche solo forzare il tasto AES.
Modifica: Dal momento che sembra che le persone stiano arrivando al cuore del problema: la crittografia su UDP, ciò che è fatto è fatto. Scriverò come lo sto facendo attualmente. È il mio progetto personale quindi accolgo con favore qualsiasi miglioramento. Non sono emotivamente attaccato al metodo attuale.
(Tutto ciò avviene su una connessione TLS esistente poiché il socket "comando" è TCP)
- A genera la chiave AES256 usando SecureRandom di java.
- A ottiene una copia della chiave pubblica di B dal server.
- A invia una chiave crittografica RSA a B utilizzando Android RSA / NONE / OAEPWithSHA1AndMGF1Padding. Questo è scelto per il padding OAEP che (da quello che ho letto) suona come il metodo migliore per rendere l'input di RSA il più casuale possibile per evitare che l'output abbia determinate caratteristiche basate sull'input.
- B riceve il messaggio e invia un comando "ok" al server che dice A.
(Il resto avviene su UDP semplice)
- A invia un messaggio a B utilizzando Android cipher's AES / GCM / NoPadding. GCM è stato scelto perché (da quello che ho letto) è il metodo migliore per "tagliare" i dati in pezzi sicuri. GCM dovrebbe contenere un MAC, quindi presumo che si occupi dell'autenticazione per me. Una nuova istanza di cifratura viene istanziata per ogni blocco di dati. Sto assumendo il cipher.init di Android si occupa della IV (nuova per ogni blocco). Dopo la crittografia. i dati vengono inviati [IV lunghezza; IV; AES256 / Dati GCM]. Da quello che ho letto il IV è come un sale che viene usato per prevenire gli attacchi precalcolati. Normalmente in un database il sale viene memorizzato in testo semplice, quindi in questo caso viene trasmesso in chiaro. (Se non è stato questo crea un problema di regressione infinita.)
- B esegue l'inverso e invia una risposta ad A usando il metodo sopra descritto.
Una nuova chiave AES256 viene utilizzata per ogni sessione tra i 2 per la segretezza in avanti. In termini di riproduzione, i dati in testo semplice hanno un numero di sequenza. Ho visto errori di decodifica MAC nei log quando si utilizza LTE all'inizio della sessione. Non ho avuto una spiegazione plausibile perché.