计时攻击
- 在密码学中,时序攻击是一种侧信道攻击,攻击者试图通过分析加密算法的时间执行来推导出密码。每一个逻辑运算在计算机需要时间来执行,根据输入不同,精确测量执行时间,根据执行时间反推出密码。
- 正常的字符串比较,一旦遇到第一个不同的字符就返回失败了,所以,理论上讲,前面只有 2 个字符相同的字符串比较的耗时,要比前面有 10 个字符相同是的比较要短,可能就少几微妙。但是,如果我们放大这个事,重复 50 次,查看平均时间,以了解哪个字符返回的时间比较长,如果某个我们要尝试的字符串的时间比较长,我们就可以确定地得出这个字符串的前面一段必然是正确的。
防止计时攻击的字符串比较函数
#include <stdio.h>
#include <ctype.h>
/** @brief 比较俩个字符串的前N个字符是否相等(区分大小写)(防止计时攻击)
* @param str1 第一个要比较的字符串
* @param str2 第二个要比较的字符串
* @param size 比较的长度
* @retval 成功返回0,失败返回非0
*/
int util_strncmp(const char * str1, const char * str2, const size_t size)
{
unsigned char result = 0;
size_t i;
if (!str1 || !str2 || !size) /* 比较固定长度的字符串。对于用户秘密来说,字符串的长度也应该属于“隐私数据” */
return -1;
for (i = 0; i < size; i++)
{
result |= str1[i] ^ str2[i];
//异或的方式不是遇到第一个不一样的字符就返回false了,而是要做全量比较,为了安全牺牲效率。
}
return result;
}
/** @brief 比较俩个字符串的前N个字符是否相等(不区分大小写)(防止计时攻击)
* @param str1 第一个要比较的字符串
* @param str2 第二个要比较的字符串
* @retval 成功返回0,失败返回非0
*/
int util_strncmp(const char * str1, const char * str2, const size_t size)
{
unsigned char result = 0;
size_t i;
if (!str1 || !str2 || !size)
return -1;
for (i = 0; i < size; i++)
{
result |= tolower(str1[i]) ^ tolower(str2[i]);
}
return result;
}