Sicurezza dello schema di crittografia ibrido

2

Voglio utilizzare uno schema di crittografia ibrido per la crittografia dei file. Lo schema deve utilizzare PKCS # 1 v1.5 - che è vulnerabile a riempire gli attacchi di Oracle - perché molte smartcard (ad esempio la scheda OpenPGP) supportano solo PKCS # 1 v1.5.

Quindi ho trovato il seguente schema (le chiavi RSA sono grandi 4096-bit, l'algoritmo simmetrico è AES-256-CTR o ChaCha-20 con chiavi a 256 bit e ovviamente vengono utilizzate chiavi diverse per la firma e la crittografia E, naturalmente, so che per i codici di streaming assolutamente IV devono essere usati con la stessa chiave):

Crittografia:

var privateSigningKey;
var publicEncryptionKey;

---   var encryptedBlock = encryptAsym(sessionKey, iV) + encryptSym(data + hash(data));
+++   var encryptedBlock = encryptAsym(sessionKey, iV) + encryptSym(data + sign(data));
var signatureBlock = sign(encryptedBlock);
var encryptedData = encryptedBlock + signatureBlock;

return encryptedData;

Decodifica:

var trustedPublicKeys[];
var signatureBlock = encryptedData.getSignatureBlock();
var encryptedBlock = encryptedData.getEncryptedBlock();
var sender = "";

for each trustedPublicKey do {
    bool signatureValid = verifySignature(encryptedBlock, signatureBlock, trustedPublicKeys[i].getSigningKey();
    if (signatureValid) sender = trustedPublicKeys[i].getName();
}

if (sender == "") exit("Untrusted signature; stopping to prevent padding oracle attacks.");

var plainDataBlock = decryptHybrid(encryptedBlock);
---   var hash = plainDataBlock.getHash();
+++   var signature = plainDataBlock.getHash();
var plainData = plainDataBlock.getPlainData();

---   if (hash != hash(plainData)) exit("Decryption failed.");
+++   if (signature != sign(plainData)) exit("Decryption failed; untrusted signature.");

return plainData;

Questo schema può essere considerato sicuro? O ci sono problemi di sicurezza o alternative migliori?

So che di solito non giri la tua cripto; ma non posso usare il formato OpenPGP perché non impedisce gli attacchi di riempimento (guarda questa domanda ) e non conosco alternative migliori.

Modifica: Schema aggiornato

    
posta K. Biermann 20.02.2015 - 13:16
fonte

1 risposta

1

Il tuo schema non protegge da un avversario che sceglie la stessa SigningKey come una festa onesta. Anche se questo non è un problema, indipendentemente dal fatto che un avversario possa falsamente "ottenere credito"
un testo in chiaro dipende ancora dai dettagli di PKCS # 1 v1.5, dal momento che dovrebbe essere impossibile
per un avversario per trovare un diverso SigningKey dannoso per il quale è probabile che accetti un
versione caricata di una coppia firma-messaggio dal privateSigningKey del mittente onesto.


Allo stesso modo, il tuo schema non protegge da un avversario che sceglie lo stesso
publicEncryptionKey come una festa onesta. Anche se quelli non erano un problema, anche se non
il tuo schema fornisce autenticità dipende comunque dai dettagli di PKCS # 1 v1.5,
dal momento che per un avversario è necessario essere inattuabili per vincere la partita seguente:
l'avversario riceve un% co_de generato onestamente e SigningKey
avversario invia un testo in chiaro publicEncryptionKey una presunta chiave di crittografia pubblica RSA data
maliciousEncryptKey e sessionKey sono generati onestamente

utilizzando maliciousEncryptKey,
iV

l'avversario vince se e solo se encryptedBlock = encryptAsym(sessionKey, iV) + encryptSym(data + sign(data))


Non sono a conoscenza di alternative "approvate". Tuttavia, la maggior parte di una buona alternativa è:
avere plainDataBlock = data + sign(data) essere qualche implementazione di crittografia autenticata una tantum

lascia che le liste tra parentesi denotino un modo per indicare senza ambiguità tutte le voci della lista
(Se tutti tranne uno di loro hanno una lunghezza nota, allora la concatenazione funzionerebbe,
altrimenti si potrebbe usare qualcosa come senza prefisso (x) || senza prefisso (y) || z.)

lascia encryptSym

lascia to_be_signed = [receiver's_name,receiver's_public_keys,data]
encryptedBlock =

ometti [encryptAsym(receiver's_public_encryption_key,sessionKey), encryptSym([sender's_name,sender's_public_keys,to_be_signed,sign(to_be_signed)] , e restituisci solo signatureBlock


Se non c'è bisogno di encryptedBlock per nascondere encryptedBlock , allora quello e
sender's_name può essere reso dati associati anziché crittografato.

Se uno è sicuro della sicurezza della CCA della crittografia a chiave pubblica, allora la parte di questa risposta
prima di questa frase, ma dopo la linea orizzontale funzionerà quasi. (Vedere l'ultimo paragrafo di questa risposta.)
Altrimenti, si dovrebbero scegliere valori distinti di uguale lunghezza sender's_public_keys e a (i bit b e 0
in entrambi gli ordini funzionerebbe bene, ma potrebbe essere più conveniente lasciarli essere interi byte),
sostituisci 1 con to_be_signed ,
e lascia a || [receiver's_name,receiver's_public_keys,data] invece di ometterlo.
Nota che in questo caso, signatureBlock = sign ( b || encryptedBlock ) di solito sarà sufficiente per dedurre signatureBlock ,
il che significa che di solito c'è pochissimo punto in cui sender's_name lo nasconde.
Bisogna anche assicurarsi che l'operazione di bracketing e lo schema delle firme siano tali che le lunghezze dei loro output non perdano nulla più del necessario sulle informazioni che dovrebbero rimanere riservate
(poiché la crittografia può perdere la lunghezza del messaggio). Come condizione sufficiente, quelli manterranno se
{le lunghezze delle rappresentazioni di lista dipendono solo dalla lunghezza delle voci e per le coppie di chiavi di firma generate onestamente, le lunghezze delle firme dipendono solo dalla lunghezza dei messaggi corrispondenti}.
Inoltre, se si desidera consentire messaggi a più destinatari, le cose sono significativamente più complicate di
cosa ho descritto in questa risposta (anche se per ragioni non correlate al resto di questo paragrafo).

    
risposta data 20.02.2015 - 14:15
fonte

Leggi altre domande sui tag