Tcl是否有任何内置函数用于以时序安全的方式比较字符串,因此没有秘密因短路而泄露?
string equal
从左边开始并返回第一个差异,因此它不适合比较秘密。
具体来说,我想比较两个sha256
HMAC。双HMAC也可以解决泄漏,但我想找到一个时间安全比较功能。
答案 0 :(得分:2)
假设您正在处理两个相同长度的字符串(例如,HMAC),那么您可以只对每个字符应用比较并累积结果:
proc safeequal {s1 s2} {
set equal 1
foreach c1 [split $s1 ""] c2 [split $s2 ""] {
set equal [expr {$equal & ($c1 eq $c2)}]
}
return $equal
}
现在,由于split
进行字符共享,可能会有一些时序效应,但是他们很难 很难利用来确定字符串的内容作为时间无法通过某个位置识别,并且在任何情况下都会降低噪音。我不能让我的系统安静到足以让我看到差异,即使在比较每个字符相等的两个字符串(大约HMAC长度)和比较每个字符不同的两个字符串之间也是如此。
% time {safeequal qwertyuiopasdfghjklzxcvbnm qwertyuiopasdfghjklzxcvbnm} 100000
9.847818689999999 microseconds per iteration
% time {safeequal qwertyuiopasdfghjklzxcvbnm QWERTYUIOPASDFGHJKLZXCVBNM} 100000
9.78685247 microseconds per iteration
% time {safeequal qwertyuiopasdfghjklzxcvbnm qwertyuiopasdfghjklzxcvbnm} 100000
9.72245421 microseconds per iteration
% time {safeequal qwertyuiopasdfghjklzxcvbnm QWERTYUIOPASDFGHJKLZXCVBNM} 100000
9.88214891 microseconds per iteration
答案 1 :(得分:1)
一个选项是使用通常的按位or
结合每个字符xor
。
# Timing safe comparision of two hashes.
#
# http://stackoverflow.com/q/35090706/2373138
proc hash_equals {hash1 hash2} {
# Get length of strings a single time.
set hash1_length [string length $hash1]
set hash2_length [string length $hash2]
# If the length is not equal, return false.
# Short circuit if they have different lengths.
# Length of the hashes is anyway known and length information
# will always be leaked because of caching effects.
if {$hash1_length != $hash2_length} {
return 0
}
set result 0
# Loop through the entire string and compare each single character.
# We compare using XOR to avoid timing effects on if branches.
for {set i 0} {$i < $hash1_length} {incr i} {
set char1 [string index $hash1 $i]
set char2 [string index $hash2 $i]
# Convert character to its ordinal value.
set ord1 [scan $char1 %c]
set ord2 [scan $char2 %c]
# Wil be 0 as long as they're the same.
set xor [expr {$ord1 ^ $ord2}]
# Once $result is not equal to 0, it will stay not equals 0.
set result [expr {$result | $xor}]
}
# Strings are exactly equal if $result is exactly 0.
return [expr {$result == 0}]
}
答案 2 :(得分:0)
如果字符串相等,则这个字符串会更快一些,但如果第一个差异在开头或结尾,则时间方面无关紧要。
proc compare {a b} {
set ary($b) 0
set ary($a) 1
set ary($b)
}
这也有效(它仍然是一个哈希表):
proc compare {a b} {
dict get [dict create $b 0 $a 1] $b
}