C++ 优化稳定常数时间阵列比较
(注:所谓“恒定时间”,我指的是当其中一个输入是固定的时,机器循环的恒定数量,而不是O(1)。这是该术语在密码学上下文中的标准含义。) 将固定值与相同大小的未知值进行比较以确保有关固定值的信息不会通过计时泄漏的最常见方法是使用XOR循环:C++ 优化稳定常数时间阵列比较,c++,c,optimization,comparison,standards,C++,C,Optimization,Comparison,Standards,(注:所谓“恒定时间”,我指的是当其中一个输入是固定的时,机器循环的恒定数量,而不是O(1)。这是该术语在密码学上下文中的标准含义。) 将固定值与相同大小的未知值进行比较以确保有关固定值的信息不会通过计时泄漏的最常见方法是使用XOR循环: bool compare(const char* fixed, const char* unknown, size_t n) { char c = 0; for (size_t i=0; i<n; ++i) c |= fi
bool compare(const char* fixed, const char* unknown, size_t n)
{
char c = 0;
for (size_t i=0; i<n; ++i)
c |= fixed[i] ^ unknown[i];
return (c == 0);
}
bool比较(常量字符*固定,常量字符*未知,大小\u t n)
{
字符c=0;
对于(size_t i=0;i而言,“仿佛”规则需要这样做,因此我认为以下方法可能有效:
bool compare(const char* p1, const char* p2, size_t n)
{
volatile char c = 0;
for (size_t i=0; i<n; ++i)
c |= p1[i] ^ p2[i];
return (c == 0);
}
即使编译器可以静态地确定函数的返回值,它仍然必须发出代码,从头到尾完整地读取两个输入数组,并在这些加载之间写入c
。优化仍然可以消除计算(XOR和OR),但内存行为将是更为明显的计时特征。从电源角度看,攻击者可能仍然能够分辨出区别
如果我们想在return语句中消除依赖于数据的分支,我们可以使用类似于Go的东西
请注意,的相关位已从C++98/03更改为C++11:
1) 在每个序列点,所有易失性对象的值都是
稳定(以前的评估已完成,新评估未完成)
开始)(直到C++11)
1) 对易失性对象的访问(读写)是严格执行的
根据它们出现的表达式的语义
特别是,它们不会被重新排序
“恒定时间”是指O(1),还是指“无论输入如何,始终以相同的时间运行,因此适合加密使用?”OP很明显是指后者。@templatetypedef:我的意思是,当其中一个输入是固定的时,比较总是以相同的机器周期数运行。换句话说,没有可用于计算固定输入值的计时端通道。在您的情况下,如果编译器静态地确定数组是相同的,则不会进行比较不需要为任何比较生成代码,对吗?它只需要将0
写入c
n
次。您正在复制OP使用n作为索引的错误…您应该指出并修复它。还有缺少的分号(和不必要的paren)在return语句中。很好。我已经修复了您指出的正确性错误,但保留了OP中的风格选择。@AlexD:两个输入可以静态地证明是相同的情况在实践中不是一个问题,因为为了进行定时攻击,其中一个输入必须由攻击者控制。但这不是问题更新:Robert Seacord(C标准委员会成员)告诉我这个答案是正确的。
bool compare(volatile const char* p1, volatile const char* p2, size_t n)
{
volatile char c = 0;
for (size_t i=0; i<n; ++i)
c |= p1[i] ^ p2[i];
return (c == 0);
}