为什么大多数c编译器都没有对这种归零代码进行优化?

时间:2016-05-22 06:41:31

标签: c security cryptography compiler-optimization

许多加密库包含类似于以下代码段的代码:

/* 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;
}

但我的天真实现并没有在优化编译器中存活下来:

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

该代码用于在释放内存之前将敏感数据归零。由于缓冲区不再使用,优化编译器假设它们可以安全地从编译的代码中删除zeriozation。

是什么阻止了第一个实施的优化?

1 个答案:

答案 0 :(得分:7)

此处的字是volatile。当变量声明为volatile时,它告诉编译器可以在该程序之外修改/访问该变量(例如通过硬件),因此它强制编译器不优化该变量并每次访问内存变量被引用。

在crypto中使用它通常是为了清除堆栈中的密钥(密钥)(局部变量)。由于堆栈用于局部变量,因此常规代码(如/* Naive zeroization implementation */中)似乎对程序的其他变量/状态没有任何影响,因此编译器可能(并且可能会)优化代码输出。为了防止它,使用volatile限定符,使编译器保留该代码并将局部变量的内存内容归零。

修改

示例:

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;
}