Perché la prima chiamata a DecryptUpdate in AES-CBC restituisce 16 byte in meno?

4

Durante la decrittografia di un file tramite la modalità CBC dell'algoritmo AES, la lunghezza dell'output è di 16 byte inferiore a quella della lunghezza di input. Ad esempio se passi un buffer di 512 byte decripta 496 byte. Succede solo in modalità CBC per la prima chiamata di EVP_DecryptUpdate() . Perché è così?

while((bytes = fread (buffer, 1, 32, fp)) != 0) 
{
    EVP_DecryptUpdate(e, buffer_out, &c_len, buffer, bytes);
    ret = fwrite(buffer_out, 1, c_len, fpout); 
    printf("c_len %d bytes %d ret %d\n", c_len, bytes, ret);
} 
    
posta Rak 27.04.2015 - 12:09
fonte

2 risposte

7

AES opera su blocchi di 16 byte. Il EVP_DecryptUpdate() funzionerà su blocchi di 16. Finché si utilizza EVP_DecryptUpdate() , si presume che gli sarà dato più dati da decrittografare e si conserverà l'ultimo blocco di dati all'interno del contesto di crypt. Questo perché in modalità CBC ha bisogno del prossimo blocco di cifratura per essere l'IV per il prossimo blocco di decrittografia perché non può prevedere quando ne avrà bisogno per calcolare il padding.

Immagine Wiki

La"lunghezza decrittografata" sarà esattamente un blocco (16 byte) inferiore a quello che gli viene dato per la prima iterazione perché conserva il secondo blocco di dati. Una volta decrittografata la seconda iterazione, emette il blocco 2 e il blocco 3 (32 byte) e mantiene il blocco 4. Estrapolandolo alla fine del file crittografato, ti renderai conto che saresti 1 blocco breve. Una volta che chiami EVP_DecryptFinal , il blocco finale viene decodificato (il padding viene preso in considerazione se necessario) e restituito al buffer specificato per i 32 blocchi completi (512 byte nell'esempio).

Codice di esempio

char *decrypt (char *key,
               char *iv,
               char *encryptedData,
               int encryptedLength)
{
    // Initialisation
    EVP_CIPHER_CTX *cryptCtx = EVP_CIPHER_CTX_new();
    EVP_CIPHER_CTX_init(cryptCtx);
    int decryptedLength = 0;
    int allocateSize = encryptedLength * sizeof(char);
    int lastDecryptLength = 0;
    char *decryptedData = (char *) malloc (allocateSize);
    memset(decryptedData, 0x00, allocateSize);
    int decryptResult = EVP_DecryptInit_ex(cryptCtx,
        EVP_bf_cbc(), NULL, key, iv);

    // EVP_DecryptInit_ex returns 1 if it succeeded.
    if (decryptResult == 1)
    {
        decryptResult = EVP_DecryptUpdate(cryptCtx, decryptedData,
            &decryptedLength, encryptedData, encryptedLength);

        // Note that EVP_DecryptUpdate will alter the value of the third parameter 
        // to be equal to the amount of data that was written. This is not always the    
        // entire length of the decrypted data! To finish the decryption process, use 
        // EVP_DecryptFinal_ex. This will decrypt any remaining data.

        // Cleanup
        if (decryptResult == 1)
        {
            // Stick the final data at the end of the last
            // decrypted data.
            EVP_DecryptFinal_ex(cryptCtx,
                decryptedData + decryptedLength,
                &lastDecryptLength);
            decryptedLength = decryptedLength + lastDecryptLength;
            decryptedData[decryptedLength – 1] = ”;
            printf ("Decrypted size: %d\n", decryptedLength);
            printf ("Decrypted data: \n%s\n\n", decryptedData);
        }
        else
        {
            printf ("EVP_DeccryptUpdate failure.\n");
        }
    }
    else
    {
        printf ("EVP_DecryptInit_ex failure.\n");
    }
    EVP_CIPHER_CTX_free(cryptCtx);
    EVP_cleanup();
    return decryptedData;
}
    
risposta data 27.04.2015 - 13:14
fonte
1

CBC è una modalità di funzionamento a blocco . Un modo per vedere le modalità operative è che il codice è in realtà un parametro per la modalità di funzionamento. In caso di operazioni CBC avverrà utilizzando la dimensione del blocco della cifra sottostante. Questo è 16 byte o 128 bit per AES.

Il problema con CBC è che richiede quei 16 byte completi, anche se questi byte non sono disponibili nell'ultimo blocco di testo in chiaro. In qualche modo questi 16 byte devono essere presenti. Di solito ciò avviene con il padding compatibile con PKCS # 7, sebbene esistano altre possibilità come il bit-padding o il criptotesto rubato (CTS).

Ora il padding PKCS # 7 è deterministico. Ciò significa che qualunque cosa sia nel testo in chiaro, l'annullamento della cancellazione avrà esito positivo. Questo non è un problema se ci sono 1.15 byte di padding, ma vuol dire che il padding di 0 byte rappresenta un problema. Se gli ultimi byte sono identici a un padding corretto rispetto al padding non è possibile distinguere tra padding e plaintext (in quanto non conosce la dimensione del testo in chiaro o del padding). La soluzione adottata dalla modalità di riempimento PKCS # 7 è quella di sempre , anche se la dimensione di input è un numero di volte superiore alla dimensione del blocco. Ecco perché il testo in chiaro di 512 byte è maggiore di 16 byte come testo cifrato - è stato aggiunto un blocco completo di riempimento durante la crittografia e rimosso durante la decrittazione . In altre parole, il padding PKCS # 7 richiede 1.16 byte per AES.

Ora il problema è che la modalità CBC di crittografia non sa quando viene raggiunta la fine del testo cifrato e quindi il padding. Ciò significa che non può restituire direttamente gli ultimi 16 byte: potrebbe essere il padding che deve essere rimosso. Quindi buffererà 16 byte fino a quando viene chiamato il metodo EVP_DecryptFinal(_ex) .

La maggior parte delle altre modalità operative trasforma il codice a blocchi in un codice di flusso (eccetto la modalità di funzionamento ECB non sicura). Quindi non avresti questo particolare problema se stai usando le modalità di funzionamento CTR, CFB o OFB. Le ciprature di flusso crittografano ogni bit, praticamente ogni byte, di testo in chiaro anche se il codice sottostante ha una dimensione di blocco maggiore.

    
risposta data 27.04.2015 - 20:11
fonte

Leggi altre domande sui tag