时间安全比较字符串

时间:2016-01-29 17:40:16

标签: string security tcl hmac

Tcl是否有任何内置函数用于以时序安全的方式比较字符串,因此没有秘密因短路而泄露?

string equal从左边开始并返回第一个差异,因此它不适合比较秘密。

具体来说,我想比较两个sha256 HMAC。双HMAC也可以解决泄漏,但我想找到一个时间安全比较功能。

3 个答案:

答案 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
}