diff options
| author | Adam Langley <agl@golang.org> | 2009-11-02 11:12:07 -0800 | 
|---|---|---|
| committer | Adam Langley <agl@golang.org> | 2009-11-02 11:12:07 -0800 | 
| commit | 7ce3d43a3703655310e6851b7595934a9508cd96 (patch) | |
| tree | cfdb4da672ba776f46400ede21b7346a4fd7b74b | |
| parent | d0ed8b09b038a10d4200d6281775160766510baa (diff) | |
| download | golang-7ce3d43a3703655310e6851b7595934a9508cd96.tar.gz | |
Split constant time functions into crypto/subtle.
R=rsc
CC=go-dev
http://go/go-review/1018020
| -rw-r--r-- | src/pkg/Make.deps | 1 | ||||
| -rw-r--r-- | src/pkg/Makefile | 1 | ||||
| -rw-r--r-- | src/pkg/crypto/rsa/pkcs1v15.go | 19 | ||||
| -rw-r--r-- | src/pkg/crypto/rsa/rsa.go | 79 | ||||
| -rw-r--r-- | src/pkg/crypto/rsa/rsa_test.go | 189 | ||||
| -rw-r--r-- | src/pkg/crypto/subtle/Makefile | 11 | ||||
| -rw-r--r-- | src/pkg/crypto/subtle/constant_time.go | 59 | ||||
| -rw-r--r-- | src/pkg/crypto/subtle/constant_time_test.go | 106 | 
8 files changed, 249 insertions, 216 deletions
| diff --git a/src/pkg/Make.deps b/src/pkg/Make.deps index 5ef36f5e2..614f48b66 100644 --- a/src/pkg/Make.deps +++ b/src/pkg/Make.deps @@ -17,6 +17,7 @@ crypto/hmac.install: crypto/md5.install crypto/sha1.install hash.install os.inst  crypto/md5.install: hash.install os.install  crypto/rc4.install: os.install strconv.install  crypto/sha1.install: hash.install os.install +crypto/subtle.install:  debug/dwarf.install: encoding/binary.install os.install strconv.install  debug/macho.install: bytes.install debug/dwarf.install encoding/binary.install fmt.install io.install os.install strconv.install  debug/elf.install: debug/dwarf.install encoding/binary.install fmt.install io.install os.install strconv.install diff --git a/src/pkg/Makefile b/src/pkg/Makefile index 61bd325db..baf2122c8 100644 --- a/src/pkg/Makefile +++ b/src/pkg/Makefile @@ -31,6 +31,7 @@ DIRS=\  	crypto/md5\  	crypto/rc4\  	crypto/sha1\ +	crypto/subtle\  	debug/dwarf\  	debug/macho\  	debug/elf\ diff --git a/src/pkg/crypto/rsa/pkcs1v15.go b/src/pkg/crypto/rsa/pkcs1v15.go index 9fb4584fe..2583f1911 100644 --- a/src/pkg/crypto/rsa/pkcs1v15.go +++ b/src/pkg/crypto/rsa/pkcs1v15.go @@ -6,6 +6,7 @@ package rsa  import (  	"bytes"; +	"crypto/subtle";  	big "gmp";  	"io";  	"os"; @@ -27,7 +28,7 @@ func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) (out []byte, er  	// EM = 0x02 || PS || 0x00 || M  	em := make([]byte, k-1);  	em[0] = 2; -	ps, mm := em[1:len(em)-len(msg)-1], em[len(em)-len(msg):len(em)]; +	ps, mm := em[1 : len(em)-len(msg)-1], em[len(em)-len(msg) : len(em)];  	err = nonZeroRandomBytes(ps, rand);  	if err != nil {  		return; @@ -77,8 +78,8 @@ func DecryptPKCS1v15SessionKey(rand io.Reader, priv *PrivateKey, ciphertext []by  		return;  	} -	valid &= constantTimeEq(int32(len(msg)), int32(len(key))); -	constantTimeCopy(valid, key, msg); +	valid &= subtle.ConstantTimeEq(int32(len(msg)), int32(len(key))); +	subtle.ConstantTimeCopy(valid, key, msg);  	return;  } @@ -96,8 +97,8 @@ func decryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (valid  	}  	em := leftPad(m.Bytes(), k); -	firstByteIsZero := constantTimeByteEq(em[0], 0); -	secondByteIsTwo := constantTimeByteEq(em[1], 2); +	firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0); +	secondByteIsTwo := subtle.ConstantTimeByteEq(em[1], 2);  	// The remainder of the plaintext must be a string of non-zero random  	// octets, followed by a 0, followed by the message. @@ -107,9 +108,9 @@ func decryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (valid  	lookingForIndex = 1;  	for i := 2; i < len(em); i++ { -		equals0 := constantTimeByteEq(em[i], 0); -		index = constantTimeSelect(lookingForIndex & equals0, i, index); -		lookingForIndex = constantTimeSelect(equals0, 0, lookingForIndex); +		equals0 := subtle.ConstantTimeByteEq(em[i], 0); +		index = subtle.ConstantTimeSelect(lookingForIndex & equals0, i, index); +		lookingForIndex = subtle.ConstantTimeSelect(equals0, 0, lookingForIndex);  	}  	valid = firstByteIsZero & secondByteIsTwo & (^lookingForIndex & 1); @@ -126,7 +127,7 @@ func nonZeroRandomBytes(s []byte, rand io.Reader) (err os.Error) {  	for i := 0; i < len(s); i++ {  		for s[i] == 0 { -			_, err = rand.Read(s[i:i+1]); +			_, err = rand.Read(s[i : i+1]);  			if err != nil {  				return;  			} diff --git a/src/pkg/crypto/rsa/rsa.go b/src/pkg/crypto/rsa/rsa.go index adc9c8f02..8ca87485a 100644 --- a/src/pkg/crypto/rsa/rsa.go +++ b/src/pkg/crypto/rsa/rsa.go @@ -8,11 +8,12 @@ package rsa  // TODO(agl): Add support for PSS padding.  import ( -		"bytes"; -	big	"gmp"; -		"hash"; -		"io"; -		"os"; +	"bytes"; +	"crypto/subtle"; +	big "gmp"; +	"hash"; +	"io"; +	"os";  )  var bigOne = big.NewInt(1) @@ -92,7 +93,7 @@ type PublicKey struct {  // A PrivateKey represents an RSA key  type PrivateKey struct { -	PublicKey;	// public part. +	PublicKey;			// public part.  	D		*big.Int;	// private exponent  	P, Q		*big.Int;	// prime factors of N  } @@ -300,58 +301,6 @@ func modInverse(a, n *big.Int) (ia *big.Int) {  	return x;  } -// 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 a if v is 1 and b if v is 0. -// Its behaviour is undefined if v takes any other value. -func constantTimeSelect(v, a, b int) int { -	return ^(v-1)&a | (v-1)&b; -} - -// constantTimeByteEq returns 1 if a == b and 0 otherwise. -func constantTimeByteEq(a, b uint8) int { -	x := ^(a^b); -	x &= x>>4; -	x &= x>>2; -	x &= x>>1; - -	return int(x); -} - -// constantTimeEq returns 1 if a == b and 0 otherwise. -func constantTimeEq(a, b int32) int { -	x := ^(a^b); -	x &= x>>16; -	x &= x>>8; -	x &= x>>4; -	x &= x>>2; -	x &= x>>1; - -	return int(x&1); -} - -// constantTimeCopy copies the contents of y into x iff v == 1. If v == 0, x is left unchanged. -// Its behaviour 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; -} -  // decrypt performs an RSA decryption, resulting in a plaintext integer. If a  // random source is given, RSA blinding is used.  func decrypt(rand io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err os.Error) { @@ -419,7 +368,7 @@ func DecryptOAEP(hash hash.Hash, rand io.Reader, priv *PrivateKey, ciphertext []  	// anything about this.)  	em := leftPad(m.Bytes(), k); -	firstByteIsZero := constantTimeByteEq(em[0], 0); +	firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0);  	seed := em[1 : hash.Size() + 1];  	db := em[hash.Size() + 1 : len(em)]; @@ -433,7 +382,7 @@ func DecryptOAEP(hash hash.Hash, rand io.Reader, priv *PrivateKey, ciphertext []  	// attacks like: J. Manger. A Chosen Ciphertext Attack on RSA Optimal  	// Asymmetric Encryption Padding (OAEP) as Standardized in PKCS #1  	// v2.0. In J. Kilian, editor, Advances in Cryptology. -	lHash2Good := constantTimeCompare(lHash, lHash2); +	lHash2Good := subtle.ConstantTimeCompare(lHash, lHash2);  	// The remainder of the plaintext must be zero or more 0x00, followed  	// by 0x01, followed by the message. @@ -445,11 +394,11 @@ func DecryptOAEP(hash hash.Hash, rand io.Reader, priv *PrivateKey, ciphertext []  	rest := db[hash.Size() : len(db)];  	for i := 0; i < len(rest); i++ { -		equals0 := constantTimeByteEq(rest[i], 0); -		equals1 := constantTimeByteEq(rest[i], 1); -		index = constantTimeSelect(lookingForIndex & equals1, i, index); -		lookingForIndex = constantTimeSelect(equals1, 0, lookingForIndex); -		invalid = constantTimeSelect(lookingForIndex & ^equals0, 1, invalid); +		equals0 := subtle.ConstantTimeByteEq(rest[i], 0); +		equals1 := subtle.ConstantTimeByteEq(rest[i], 1); +		index = subtle.ConstantTimeSelect(lookingForIndex & equals1, i, index); +		lookingForIndex = subtle.ConstantTimeSelect(equals1, 0, lookingForIndex); +		invalid = subtle.ConstantTimeSelect(lookingForIndex & ^equals0, 1, invalid);  	}  	if firstByteIsZero & lHash2Good & ^invalid & ^lookingForIndex != 1 { diff --git a/src/pkg/crypto/rsa/rsa_test.go b/src/pkg/crypto/rsa/rsa_test.go index df0d160dd..3bdfc66a7 100644 --- a/src/pkg/crypto/rsa/rsa_test.go +++ b/src/pkg/crypto/rsa/rsa_test.go @@ -5,12 +5,11 @@  package rsa  import ( -		"bytes"; -		"crypto/sha1"; -	big	"gmp"; -		"os"; -		"testing"; -		"testing/quick"; +	"bytes"; +	"crypto/sha1"; +	big "gmp"; +	"os"; +	"testing";  )  func TestKeyGeneration(t *testing.T) { @@ -109,101 +108,6 @@ func TestDecryptOAEP(t *testing.T) {  	}  } -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); -	} -} -  // testEncryptOAEPData contains a subset of the vectors from RSA's "Test vectors for RSA-OAEP".  var testEncryptOAEPData = []testEncryptOAEPStruct{  	// Key 1 @@ -305,47 +209,48 @@ var testEncryptOAEPData = []testEncryptOAEPStruct{  		65537,  		"056b04216fe5f354ac77250a4b6b0c8525a85c59b0bd80c56450a22d5f438e596a333aa875e291dd43f48cb88b9d5fc0d499f9fcd1c397f9afc070cd9e398c8d19e61db7c7410a6b2675dfbf5d345b804d201add502d5ce2dfcb091ce9997bbebe57306f383e4d588103f036f7e85d1934d152a323e4a8db451d6f4a5b1b0f102cc150e02feee2b88dea4ad4c1baccb24d84072d14e1d24a6771f7408ee30564fb86d4393a34bcf0b788501d193303f13a2284b001f0f649eaf79328d4ac5c430ab4414920a9460ed1b7bc40ec653e876d09abc509ae45b525190116a0c26101848298509c1c3bf3a483e7274054e15e97075036e989f60932807b5257751e79",  		[]testEncryptOAEPMessage{ -		// Example 10.1 -		testEncryptOAEPMessage{ -			[]byte{0x8b, 0xba, 0x6b, 0xf8, 0x2a, 0x6c, 0x0f, 0x86, -				0xd5, 0xf1, 0x75, 0x6e, 0x97, 0x95, 0x68, 0x70, 0xb0, -				0x89, 0x53, 0xb0, 0x6b, 0x4e, 0xb2, 0x05, 0xbc, 0x16, -				0x94, 0xee, -			}, -			[]byte{0x47, 0xe1, 0xab, 0x71, 0x19, 0xfe, 0xe5, 0x6c, -				0x95, 0xee, 0x5e, 0xaa, 0xd8, 0x6f, 0x40, 0xd0, 0xaa, -				0x63, 0xbd, 0x33, -			}, -			[]byte{0x53, 0xea, 0x5d, 0xc0, 0x8c, 0xd2, 0x60, 0xfb, -				0x3b, 0x85, 0x85, 0x67, 0x28, 0x7f, 0xa9, 0x15, 0x52, -				0xc3, 0x0b, 0x2f, 0xeb, 0xfb, 0xa2, 0x13, 0xf0, 0xae, -				0x87, 0x70, 0x2d, 0x06, 0x8d, 0x19, 0xba, 0xb0, 0x7f, -				0xe5, 0x74, 0x52, 0x3d, 0xfb, 0x42, 0x13, 0x9d, 0x68, -				0xc3, 0xc5, 0xaf, 0xee, 0xe0, 0xbf, 0xe4, 0xcb, 0x79, -				0x69, 0xcb, 0xf3, 0x82, 0xb8, 0x04, 0xd6, 0xe6, 0x13, -				0x96, 0x14, 0x4e, 0x2d, 0x0e, 0x60, 0x74, 0x1f, 0x89, -				0x93, 0xc3, 0x01, 0x4b, 0x58, 0xb9, 0xb1, 0x95, 0x7a, -				0x8b, 0xab, 0xcd, 0x23, 0xaf, 0x85, 0x4f, 0x4c, 0x35, -				0x6f, 0xb1, 0x66, 0x2a, 0xa7, 0x2b, 0xfc, 0xc7, 0xe5, -				0x86, 0x55, 0x9d, 0xc4, 0x28, 0x0d, 0x16, 0x0c, 0x12, -				0x67, 0x85, 0xa7, 0x23, 0xeb, 0xee, 0xbe, 0xff, 0x71, -				0xf1, 0x15, 0x94, 0x44, 0x0a, 0xae, 0xf8, 0x7d, 0x10, -				0x79, 0x3a, 0x87, 0x74, 0xa2, 0x39, 0xd4, 0xa0, 0x4c, -				0x87, 0xfe, 0x14, 0x67, 0xb9, 0xda, 0xf8, 0x52, 0x08, -				0xec, 0x6c, 0x72, 0x55, 0x79, 0x4a, 0x96, 0xcc, 0x29, -				0x14, 0x2f, 0x9a, 0x8b, 0xd4, 0x18, 0xe3, 0xc1, 0xfd, -				0x67, 0x34, 0x4b, 0x0c, 0xd0, 0x82, 0x9d, 0xf3, 0xb2, -				0xbe, 0xc6, 0x02, 0x53, 0x19, 0x62, 0x93, 0xc6, 0xb3, -				0x4d, 0x3f, 0x75, 0xd3, 0x2f, 0x21, 0x3d, 0xd4, 0x5c, -				0x62, 0x73, 0xd5, 0x05, 0xad, 0xf4, 0xcc, 0xed, 0x10, -				0x57, 0xcb, 0x75, 0x8f, 0xc2, 0x6a, 0xee, 0xfa, 0x44, -				0x12, 0x55, 0xed, 0x4e, 0x64, 0xc1, 0x99, 0xee, 0x07, -				0x5e, 0x7f, 0x16, 0x64, 0x61, 0x82, 0xfd, 0xb4, 0x64, -				0x73, 0x9b, 0x68, 0xab, 0x5d, 0xaf, 0xf0, 0xe6, 0x3e, -				0x95, 0x52, 0x01, 0x68, 0x24, 0xf0, 0x54, 0xbf, 0x4d, -				0x3c, 0x8c, 0x90, 0xa9, 0x7b, 0xb6, 0xb6, 0x55, 0x32, -				0x84, 0xeb, 0x42, 0x9f, 0xcc, +			// Example 10.1 +			testEncryptOAEPMessage{ +				[]byte{0x8b, 0xba, 0x6b, 0xf8, 0x2a, 0x6c, 0x0f, 0x86, +					0xd5, 0xf1, 0x75, 0x6e, 0x97, 0x95, 0x68, 0x70, 0xb0, +					0x89, 0x53, 0xb0, 0x6b, 0x4e, 0xb2, 0x05, 0xbc, 0x16, +					0x94, 0xee, +				}, +				[]byte{0x47, 0xe1, 0xab, 0x71, 0x19, 0xfe, 0xe5, 0x6c, +					0x95, 0xee, 0x5e, 0xaa, 0xd8, 0x6f, 0x40, 0xd0, 0xaa, +					0x63, 0xbd, 0x33, +				}, +				[]byte{0x53, 0xea, 0x5d, 0xc0, 0x8c, 0xd2, 0x60, 0xfb, +					0x3b, 0x85, 0x85, 0x67, 0x28, 0x7f, 0xa9, 0x15, 0x52, +					0xc3, 0x0b, 0x2f, 0xeb, 0xfb, 0xa2, 0x13, 0xf0, 0xae, +					0x87, 0x70, 0x2d, 0x06, 0x8d, 0x19, 0xba, 0xb0, 0x7f, +					0xe5, 0x74, 0x52, 0x3d, 0xfb, 0x42, 0x13, 0x9d, 0x68, +					0xc3, 0xc5, 0xaf, 0xee, 0xe0, 0xbf, 0xe4, 0xcb, 0x79, +					0x69, 0xcb, 0xf3, 0x82, 0xb8, 0x04, 0xd6, 0xe6, 0x13, +					0x96, 0x14, 0x4e, 0x2d, 0x0e, 0x60, 0x74, 0x1f, 0x89, +					0x93, 0xc3, 0x01, 0x4b, 0x58, 0xb9, 0xb1, 0x95, 0x7a, +					0x8b, 0xab, 0xcd, 0x23, 0xaf, 0x85, 0x4f, 0x4c, 0x35, +					0x6f, 0xb1, 0x66, 0x2a, 0xa7, 0x2b, 0xfc, 0xc7, 0xe5, +					0x86, 0x55, 0x9d, 0xc4, 0x28, 0x0d, 0x16, 0x0c, 0x12, +					0x67, 0x85, 0xa7, 0x23, 0xeb, 0xee, 0xbe, 0xff, 0x71, +					0xf1, 0x15, 0x94, 0x44, 0x0a, 0xae, 0xf8, 0x7d, 0x10, +					0x79, 0x3a, 0x87, 0x74, 0xa2, 0x39, 0xd4, 0xa0, 0x4c, +					0x87, 0xfe, 0x14, 0x67, 0xb9, 0xda, 0xf8, 0x52, 0x08, +					0xec, 0x6c, 0x72, 0x55, 0x79, 0x4a, 0x96, 0xcc, 0x29, +					0x14, 0x2f, 0x9a, 0x8b, 0xd4, 0x18, 0xe3, 0xc1, 0xfd, +					0x67, 0x34, 0x4b, 0x0c, 0xd0, 0x82, 0x9d, 0xf3, 0xb2, +					0xbe, 0xc6, 0x02, 0x53, 0x19, 0x62, 0x93, 0xc6, 0xb3, +					0x4d, 0x3f, 0x75, 0xd3, 0x2f, 0x21, 0x3d, 0xd4, 0x5c, +					0x62, 0x73, 0xd5, 0x05, 0xad, 0xf4, 0xcc, 0xed, 0x10, +					0x57, 0xcb, 0x75, 0x8f, 0xc2, 0x6a, 0xee, 0xfa, 0x44, +					0x12, 0x55, 0xed, 0x4e, 0x64, 0xc1, 0x99, 0xee, 0x07, +					0x5e, 0x7f, 0x16, 0x64, 0x61, 0x82, 0xfd, 0xb4, 0x64, +					0x73, 0x9b, 0x68, 0xab, 0x5d, 0xaf, 0xf0, 0xe6, 0x3e, +					0x95, 0x52, 0x01, 0x68, 0x24, 0xf0, 0x54, 0xbf, 0x4d, +					0x3c, 0x8c, 0x90, 0xa9, 0x7b, 0xb6, 0xb6, 0x55, 0x32, +					0x84, 0xeb, 0x42, 0x9f, 0xcc, +				},  			}, -		}}, +		},  	},  } diff --git a/src/pkg/crypto/subtle/Makefile b/src/pkg/crypto/subtle/Makefile new file mode 100644 index 000000000..4d245c683 --- /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 000000000..a1d2eaf99 --- /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 000000000..78aa6771d --- /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); +	} +} | 
