Split constant time functions into crypto/subtle. R=rsc CC=go-dev http://go/go-review/1018020
diff --git a/src/pkg/crypto/subtle/Makefile b/src/pkg/crypto/subtle/Makefile new file mode 100644 index 0000000..4d245c6 --- /dev/null +++ b/src/pkg/crypto/subtle/Makefile
@@ -0,0 +1,11 @@ +# Copyright 2009 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +include $(GOROOT)/src/Make.$(GOARCH) + +TARG=crypto/subtle +GOFILES=\ + constant_time.go\ + +include $(GOROOT)/src/Make.pkg
diff --git a/src/pkg/crypto/subtle/constant_time.go b/src/pkg/crypto/subtle/constant_time.go new file mode 100644 index 0000000..a1d2eaf --- /dev/null +++ b/src/pkg/crypto/subtle/constant_time.go
@@ -0,0 +1,59 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This package implements functions that are often useful in cryptographic +// code but require careful thought to use correctly. +package subtle + +// ConstantTimeCompare returns 1 iff the two equal length slices, x +// and y, have equal contents. The time taken is a function of the length of +// the slices and is independent of the contents. +func ConstantTimeCompare(x, y []byte) int { + var v byte; + + for i := 0; i < len(x); i++ { + v |= x[i]^y[i]; + } + + return ConstantTimeByteEq(v, 0); +} + +// ConstantTimeSelect returns x if v is 1 and y if v is 0. +// Its behavior is undefined if v takes any other value. +func ConstantTimeSelect(v, x, y int) int { + return ^(v-1) & x | (v-1)&y; +} + +// ConstantTimeByteEq returns 1 if x == x and 0 otherwise. +func ConstantTimeByteEq(x, y uint8) int { + z := ^(x^y); + z &= z>>4; + z &= z>>2; + z &= z>>1; + + return int(z); +} + +// ConstantTimeEq returns 1 if x == y and 0 otherwise. +func ConstantTimeEq(x, y int32) int { + z := ^(x^y); + z &= z>>16; + z &= z>>8; + z &= z>>4; + z &= z>>2; + z &= z>>1; + + return int(z&1); +} + +// ConstantTimeCopy copies the contents of y into x iff v == 1. If v == 0, x is left unchanged. +// Its behavior is undefined if v takes any other value. +func ConstantTimeCopy(v int, x, y []byte) { + xmask := byte(v-1); + ymask := byte(^(v-1)); + for i := 0; i < len(x); i++ { + x[i] = x[i]&xmask | y[i]&ymask; + } + return; +}
diff --git a/src/pkg/crypto/subtle/constant_time_test.go b/src/pkg/crypto/subtle/constant_time_test.go new file mode 100644 index 0000000..78aa677 --- /dev/null +++ b/src/pkg/crypto/subtle/constant_time_test.go
@@ -0,0 +1,106 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package subtle + +import ( + "bytes"; + "testing"; + "testing/quick"; +) + +type TestConstantTimeCompareStruct struct { + a, b []byte; + out int; +} + +var testConstandTimeCompareData = []TestConstantTimeCompareStruct{ + TestConstantTimeCompareStruct{[]byte{}, []byte{}, 1}, + TestConstantTimeCompareStruct{[]byte{0x11}, []byte{0x11}, 1}, + TestConstantTimeCompareStruct{[]byte{0x12}, []byte{0x11}, 0}, +} + +func TestConstantTimeCompare(t *testing.T) { + for i, test := range testConstandTimeCompareData { + if r := ConstantTimeCompare(test.a, test.b); r != test.out { + t.Errorf("#%d bad result (got %x, want %x)", i, r, test.out); + } + } +} + +type TestConstantTimeByteEqStruct struct { + a, b uint8; + out int; +} + +var testConstandTimeByteEqData = []TestConstantTimeByteEqStruct{ + TestConstantTimeByteEqStruct{0, 0, 1}, + TestConstantTimeByteEqStruct{0, 1, 0}, + TestConstantTimeByteEqStruct{1, 0, 0}, + TestConstantTimeByteEqStruct{0xff, 0xff, 1}, + TestConstantTimeByteEqStruct{0xff, 0xfe, 0}, +} + +func byteEq(a, b uint8) int { + if a == b { + return 1; + } + return 0; +} + +func TestConstantTimeByteEq(t *testing.T) { + for i, test := range testConstandTimeByteEqData { + if r := ConstantTimeByteEq(test.a, test.b); r != test.out { + t.Errorf("#%d bad result (got %x, want %x)", i, r, test.out); + } + } + err := quick.CheckEqual(ConstantTimeByteEq, byteEq, nil); + if err != nil { + t.Error(err); + } +} + +func eq(a, b int32) int { + if a == b { + return 1; + } + return 0; +} + +func TestConstantTimeEq(t *testing.T) { + err := quick.CheckEqual(ConstantTimeEq, eq, nil); + if err != nil { + t.Error(err); + } +} + +func copy(v int, x, y []byte) []byte { + if len(x) > len(y) { + x = x[0:len(y)]; + } else { + y = y[0:len(x)]; + } + if v == 1 { + bytes.Copy(x, y); + } + return x; +} + +func constantTimeCopyWrapper(v int, x, y []byte) []byte { + if len(x) > len(y) { + x = x[0:len(y)]; + } else { + y = y[0:len(x)]; + } + v &= 1; + ConstantTimeCopy(v, x, y); + return x; +} + +func TestConstantTimeCopy(t *testing.T) { + err := quick.CheckEqual(constantTimeCopyWrapper, copy, nil); + if err != nil { + t.Error(err); + } +}