go crypto/subtle: change ConstantTimeLessOrEq to have less undefined behaviour

q0qdq0h2  于 4个月前  发布在  Go
关注(0)|答案(7)|浏览(44)

What version of Go are you using ( go version )?

$ go version
go1.11.6

Does this issue reproduce with the latest release?

Yes. (With apologies for my vintage go compiler.)

What operating system and processor architecture are you using ( go env )?

go env Output

$ go env
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/isis/.cache/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/isis/go"
GOPROXY=""
GORACE=""
GOROOT="/usr/lib/go-1.11"
GOTMPDIR=""
GOTOOLDIR="/usr/lib/go-1.11/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build154905218=/tmp/go-build -gno-record-gcc-switches"

What did you do?

I have a better algorithm for the ConstantTimeLessOrEq function which works for all inputs in [0, 2^32). Currently the ConstantTimeLessOrEq function only works (as documented) for inputs in [0, 2^31) and is UB for everything else (including negative signed integers, which it takes signed ints). Implementing the algorithm and testing it shows that it works for correctly for positive inputs, which means we could also change the interface to be ConstantTimeLessOrEq(x, y uint32) int which would remove all UB, but this is obviously a decision for the maintainers.
The algorithm is:

// ConstantTimeLessOrEq returns 1 if x <= y and 0 otherwise.                                                                                                                                                                                   
// Its behavior is undefined if x or y are negative.                                                                                                                                                                                           
func ConstantTimeLessOrEq(x, y int) int {                                                                                                                                                                                                      
    x32 := uint32(x)                                                                                                                                                                                                                           
    y32 := uint32(y)                                                                                                                                                                                                                           
                                                                                                                                                                                                                                               
    gtb := x32 & ^y32                                                                                                                                                                                                                          
    ltb := ^x32 & y32                                                                                                                                                                                                                          
                                                                                                                                                                                                                                               
    ltb = ltb | (ltb >> 1)                                                                                                                                                                                                                     
    ltb = ltb | (ltb >> 2)                                                                                                                                                                                                                     
    ltb = ltb | (ltb >> 4)                                                                                                                                                                                                                     
    ltb = ltb | (ltb >> 16)                                                                                                                                                                                                                    
                                                                                                                                                                                                                                               
    bit := gtb & ^ltb                                                                                                                                                                                                                          
                                                                                                                                                                                                                                               
    bit = bit | (bit >> 1)                                                                                                                                                                                                                     
    bit = bit | (bit >> 2)                                                                                                                                                                                                                     
    bit = bit | (bit >> 4)                                                                                                                                                                                                                     
    bit = bit | (bit >> 16)                                                                                                                                                                                                                    
                                                                                                                                                                                                                                               
    return int(^bit & 1)                                                                                                                                                                                                                       
}

What did you expect to see?

N/A.

What did you see instead?

EDIT: This is obvious but an example test case which (expectedly) fails the previous algorithm is:

{1, 4294967295, 1},

EDIT #2 : Perhaps less obvious, this algorithm also implements ConstantTimeGreater by changing the final line to return int(bit & 1) , which is also useful for some of the algorithms in a few post-quantum cryptographic algorithms, particularly those which require a constant-time sorting network .

fcwjkofz

fcwjkofz1#

https://golang.org/cl/270959提到了这个问题:crypto/subtle: remove undefined behaviour from ConstantTimeLessOrEq

gtlvzcf8

gtlvzcf83#

由于我们目前正在冻结Go 1.16的代码,您能否澄清一下,您是打算将这个问题留给1.17还是1.16?请参见https://github.com/golang/go/wiki/Go-Release-Cycle

特别是,如果这被认为是一个用户难以轻松解决的错误或问题,那么您可能可以主张在冻结期间进行审查和合并,并在两个月后与1.16一起发布。否则,它将等待8个月后的1.17版本。

raogr8fs

raogr8fs4#

我已经将此添加到待办事项里程碑,同时@mvdan的问题正在得到解答。

cig3rfwq

cig3rfwq5#

感谢@isislovecruft!
正如您所说,目前按照文档进行操作,因此这应该针对Go 1.17版本,因为Go 1.16版本已经进入代码冻结阶段。

fhg3lkii

fhg3lkii6#

Hi, 我现在无法对CL进行评论,但我认为算法是错误的。还没有机会进一步研究它。

```go
package main

import (
 "crypto/subtle"
 "fmt"
)

func main() {
 x := 342
 y := 255
}

// golang.org/issues/42685
func ConstantTimeLessOrEq(x, y int) bool {
 x32 := uint32(x)
 y32 := uint32(y)
 return subtle.ConstantTimeCompare([]byte(strconv.Itoa(x)), []byte(strconv.Itoa(y))) == 1
}
kmbjn2e3

kmbjn2e37#

啊,本身没有错。只是缺少 ltb = ltb | (ltb >> 8)bit ,它们也在 CL 上发布。

相关问题