有时,出于安全考虑,我们需要将内存清零以防止无意中访问敏感数据,比如在加密某些数据后安全地删除密钥.大多数人建议这样做的方法是将随机数据写入包含敏感信息的数组,因为编译器无法对其进行优化.众所周知,memset如果它是在数据超出范围之前对数据进行的最后一次操作,那么由于as-if规则,优化编译器可以优化掉这些函数的天真使用.但是,获取和写入随机数据的速度很慢,我可能已经找到了解决方案.在将其部署到生产代码中之前,我想要一个专家意见.
根据运算符的本质,将任何东西与自身相混合,总是得到零值,而且速度非常快.遍历内存块并将其与自身进行对比似乎是解决归零问题的一种非常有效的解决方案,但我担心它可以通过足够好的优化编译器进行优化.它是跨平台和可移植的,除了使用size_t数据类型外,它不需要使用标准库.我已经在下面列出了我的意思的参考实现.在其中我有一个函数调用nuke,它接受一个指针data_to_zero并迭代xor的size字节与自己.
void nuke (void *data_to_zero, size_t size)
{
size_t i;
for (i = 0; i < size; i++) {
((unsigned char*)data_to_zero)[i] ^= ((unsigned char*)data_to_zero)[i];
}
}
Run Code Online (Sandbox Code Playgroud)
这种实现相当慢,但明显快于获取足够随机的数据并将其写入data.优化后,它比memset我可以访问的实现更快,这是令人惊讶的.
我还没有学习汇编,但是在O2和O3级别的GCC和Clang优化之后的汇编输出64位x86处理器xorl在代码中的某个地方有指令,有时两次.这向我表明,记忆的实际情况正在发生,但我希望有人知道他们正在谈论什么以确认.
这是一个可行的解决方案?