2016-05-22 3 views
2

De nombreuses bibliothèques incluent un code crypto similaire à l'extrait suivant:Pourquoi ce code de mise à zéro n'est-il pas optimisé par la plupart des compilateurs c?

/* Implementation that should never be optimized out by the compiler */ 
static void optimize_proof_zeroize(void *v, size_t n) 
{ 
    volatile unsigned char *p = v; 
    while(n--) *p++ = 0; 
} 

Mais ma mise en œuvre naïve ne survit pas à un compilateur optimisé:

/* Naive zeroization implementation */ 
static void naive_zeroize(unsigned char *c, size_t n) 
{ 
    int i; 
    for(i = 0; i < n; i++) 
     c[i] = 0; 
} 

Le code est utilisé pour mettre à zéro les données sensibles avant de libérer la Mémoire. Étant donné que le tampon n'est pas utilisé à nouveau, les compilateurs d'optimisation supposent qu'ils peuvent supprimer en toute sécurité la zeriozation à partir du code compilé. Qu'est-ce qui empêche la première implémentation d'être optimisée?

+4

Vous pouvez en savoir plus sur ([le qualificatif 'volatile'] http://en.cppreference.com/w/c/language/ volatil). –

+1

Je ne vois aucune raison pour laquelle les extraits seraient optimisés. Vous pouvez peut-être [modifier] votre question pour inclure une description de la raison pour laquelle vous pensez que le deuxième extrait doit être optimisé. –

Répondre

6

La clé est volatile. Lorsqu'une variable est déclarée volatile, elle indique au compilateur que cette variable peut être modifiée/accédée en dehors de ce programme (par exemple par du matériel), obligeant ainsi le compilateur à ne pas optimiser cette variable et accéder à la mémoire chaque fois que cette variable est référencée.

Son utilisation en crypto consiste généralement à effacer le secret (clés) de la pile (variables locales). Puisque la pile est utilisée pour la variable locale, le code normal (comme dans votre /* Naive zeroization implementation */) pourrait ne pas avoir d'impact sur les autres variables/état du programme, ainsi le compilateur pourrait (et probablement) optimiser ce code. Pour l'empêcher, le qualificateur volatile est utilisé ce qui oblige le compilateur à quitter ce code et à mettre à zéro le contenu de la mémoire des variables locales.

Modifier

Exemple:

void decrypt(void* src, void* dest, crypto_stuff_t* params) 
{ 
    crypto_key_t decryption_key; // will hold the decryption key 
    .... 
    .... 
    // end of flow 
    // we want to zero the content of decryption_key, otherwise its value 
    // will remain on the stack 
    // this: 
    // decryption_key <-- 0; 
    // will be just optimized out by the compiler 
    // but this won't: 
    volatile uint8_t* key_ptr = (uint8_t*)&decryption_key; 
    int i; 
    for(i = 0; i < sizeof(crypto_key_t); i++) 
     key_ptr[i] = 0; 
}