Domande sulla crittografia ibrida. RSA con AES

1

Voglio usare una crittografia ibrida nella mia applicazione, quindi dopo aver letto un sacco di righe ho finito con questa implementazione, per favore lo crititi;) (Voglio attenermi a .Net)

byte[] aesKey = GetRandomBytes(256); // 256 Bits with RNGCryptoServiceProvider
byte[] aesIV = GetRandomBytes(128); // 128 Bits with RNGCryptoServiceProvider

Domanda: Dovrei crittografare l'IV, a mio avviso questo sarebbe solo l'oscurità attraverso la segretezza e non aggiungere nulla alla mia secrità.

Ora crittografo aesKey e aesIV con ogni PublicKey (Recipient).

foreach (RSACryptoServiceProvider key in keys)
{
    var data = new EncryptedData();
    data.Data = key.Encrypt(bytes, true); // with OAEP padding
    data.Fingerprint = CreateFingerprint(key); // SHA1 from the public key
    list.Add(data);
}

Domanda: se non si memorizza l'impronta digitale, è trattabile?
Domanda: ho letto che il padding sbagliato potrebbe essere un problema di sicurezza, ma cosa succede se criptico una chiave aes casuale?

Se un 'segno' passato == true 'Firmo i dati con ogni PrivateKey (Sender), in caso normale una chiave.

if (sign)
{
    foreach (RSACryptoServiceProvider key in privateKeys)
    {
        var hash = new SHA512Managed();
        byte[] hashBytes = hash.ComputeHash(data);
        byte[] signHash = key.SignHash(hashBytes, CryptoConfig.MapNameToOID("SHA512"));
        var item = new EncryptedData
            {
                Data = signHash,
                Fingerprint = CreateFingerprint(key)
            };
        encryptedData.Signatures.Add(item);
    }
}

Domanda: RSACryptoServiceProvider.SignHash rappresenta il metodo giusto? (O SignData?)
Domanda: Trovo approcci diversi, alcuni vogliono firmare i dati semplici e altri crittografati. Cosa ne pensi?

Ora crittografo i dati effettivi

using (var rijAlg = new RijndaelManaged())
{
    rijAlg.KeySize = 256;
    rijAlg.Key = aesKey;
    rijAlg.IV = aesIV;
    rijAlg.Mode = CipherModeTextMode; // CipherMode.CBC
    rijAlg.Padding = PaddingModeTextMode; // PaddingMode.ISO10126, pad with random data

    using (var stream = new MemoryStream())
    using (ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV))
    using (var encrypt = new CryptoStream(stream, encryptor, CryptoStreamMode.Write))
    {
        encrypt.Write(data, 0, data.Length);
        encrypt.FlushFinalBlock();
        return stream.ToArray();
    }
}

Alla fine searlize questo oggetto e invio a Bob.

public class EncryptedDataHolder
{
    public IEnumerable<EncryptedData> EncryptedAesKeys { get; set; }

    public IEnumerable<EncryptedData> EncryptedAesIVs { get; set; }

    public IEnumerable<EncryptedData> Signatures { get; set; }

    public byte[] EncryptedContent { get; set; }
}

public class EncryptedData
{
    public byte[] Data { get; set; }
    public byte[] Fingerprint { get; set; }
}

Domanda: aggiungere / rimuovere informazioni?

Ho visto questo grafico su link
link
Quindi penso che dovrei usare una chiave RSA a 16384 bit per soddisfare il livello di sicurezza di aes 256. Funziona con csp = new RSACryptoServiceProvider(16384); ma richiede alcuni minuti.
Domanda: Questo approccio è ragionevole?

Grazie mille!

    
posta dh_cgn 29.03.2013 - 11:57
fonte

2 risposte

2

Per capire perché ha senso crittografare un IV per la modalità CBC. Devi capire che ogni blocco è crittografato separatamente e utilizza il blocco di testo cifrato precedente come "IV", quindi se ottengo magicamente la chiave, ma non la IV, posso decodificare tutto tranne il primo blocco di dati. Quindi il seguente ha più senso:

public class EncryptedDataHolder
{
    public IEnumerable<EncryptedData> EncryptedAesKeys { get; set; }

    public IEnumerable<EncryptedData> Signatures { get; set; }

    public byte[]  ContentIV { get; set; }

    public byte[] EncryptedContent { get; set; }
}

Il contatore standard per riempire oracoli (o altri attacchi di testo in chiaro scelti) è crittografia autenticata , convalidando che il testo cifrato di EncryptedContent è autentico prima di operare sui dati decodificati è ciò che è importante.

public class EncryptedDataHolder
{
    public IEnumerable<EncryptedData> EncryptedAesKeys { get; set; }

    public IEnumerable<EncryptedData> EncryptedHmacKeys { get; set; }

    public IEnumerable<EncryptedData> Signatures { get; set; }

    public byte[]  ContentIV { get; set; }

    public byte[] EncryptedContent { get; set; }

    public byte[]  ContentMAC { get; set; }
}

Quanto sopra si sta facendo disordinato, quindi potresti probabilmente refactificare EncryptedData in EncryptedKeys e contenere 2 chiavi crittografate, 1 firma per entrambi e un'impronta digitale.

SignData eseguirà solo un hash sha1 nelle .net api, dato che hai voluto sha512, fai ciò che stai facendo con SignHash.

Firma le chiavi crittografate, non le chiavi non formattate, trattando in modo simile il testo in chiaro decrittografato delle chiavi prima di verificare che la firma abbia un alto potenziale di perdita di informazioni del testo in chiaro.

L'implementazione della tua decifrazione manca completamente dalla tua domanda di ragionevolezza ed è l'area più incline per errori di implementazione che perdono dati sul testo in chiaro.

Detto questo, consiglio vivamente di vedere se è possibile utilizzare una libreria ad alto livello per soddisfare i propri scopi Keyczar non supporta un testo cifrato multikey relativo alla casella, ma potrebbe essere possibile utilizzarlo per supportarlo o si potrebbe essere in grado di ripensare un modo in cui non è necessario crittografare con più chiavi rsa per lo stesso testo cifrato.

    
risposta data 29.03.2013 - 15:33
fonte
2

L'IV serve semplicemente a prevenire l'analisi differenziale tra due diversi messaggi. È perfettamente normale essere pubblico e in effetti deve essere accessibile per la decrittazione.

La crittografia per un utente con la sua chiave pubblica non rende dichiarazioni sull'autenticazione. Non è una firma, quindi la negabilità è irrilevante. Non esiste una firma per attestare il proprietario originale.

Ci sono dei punti deboli nell'usare il riempimento sbagliato per alcuni algoritmi. Non so se ce ne sono di particolarmente deboli quando utilizzi un valore più o meno casuale per i tuoi dati, ma perché rischiare?

Non ho familiarità con la particolare libreria, ma secondo i commenti che ho ricevuto, SignHash firma un hash precalcolato dove SignData calcola l'hash e firma. SignData sarebbe probabilmente migliore, ma non ho molta familiarità con quella libreria esatta, quindi questa risposta potrebbe non essere corretta. Si noti che la firma lo renderebbe innegabile in quanto dimostra la proprietà originale. Se non vuoi provare la proprietà originale, la firma è inutile e controproducente, in quanto un utente malintenzionato potrebbe anche firmarlo e non ci sarebbe alcun modo per capire se fosse autentico o meno.

Sembra una bella copia della crittografia asimmetrica di una chiave dati simmetrica. Sarebbe utile includere le chiavi pubbliche accoppiate con le chiavi AES crittografate. Ciò aiuterà le persone a cercare la chiave corretta sul portachiavi da utilizzare per la decodifica. Altrimenti dovrebbero provarli tutti per trovare quello che sblocca la loro chiave privata. Neanche a infastidire la crittografia degli IV, si tratta di dati duplicati e non deve essere sicuro. Se è necessaria una firma, non conservare una raccolta di firme, firmare il carico utile crittografato principale una volta per tutti. La firma del portachiavi non è necessaria in quanto una chiave modificata non decrittografa il carico utile.

L'approccio sembra ragionevole e in linea con gli approcci standard per affrontarlo. Probabilmente non è l'implementazione più solida in circolazione, ma non vedo anche problemi super-abbaglianti. Potresti prendere in considerazione la ricerca di una libreria esistente che gestisca la stessa cosa anche se non stai facendo nulla di unico. (Anche se non è davvero un tuo problema, dato che stai usando algoritmi consolidati.)

    
risposta data 29.03.2013 - 13:58
fonte

Leggi altre domande sui tag