Merge branch 'align_key_and_ecdsa_nonce_entropy' of https://github.com/Gustav-Simonsson/go-ethereum into Gustav-Simonsson-align_key_and_ecdsa_nonce_entropy
This commit is contained in:
		
						commit
						12b2d57629
					
				| @ -68,10 +68,10 @@ import ( | ||||
| 	"code.google.com/p/go.crypto/scrypt" | ||||
| 	"crypto/aes" | ||||
| 	"crypto/cipher" | ||||
| 	crand "crypto/rand" | ||||
| 	"encoding/hex" | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"github.com/ethereum/go-ethereum/crypto/randentropy" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"path" | ||||
| @ -116,7 +116,7 @@ func (ks keyStorePassphrase) GetKeyAddresses() (addresses [][]byte, err error) { | ||||
| 
 | ||||
| func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) { | ||||
| 	authArray := []byte(auth) | ||||
| 	salt := GetEntropyCSPRNG(32) | ||||
| 	salt := randentropy.GetEntropyMixed(32) | ||||
| 	derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptr, scryptp, scryptdkLen) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| @ -131,7 +131,7 @@ func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	iv := GetEntropyCSPRNG(aes.BlockSize) // 16
 | ||||
| 	iv := randentropy.GetEntropyMixed(aes.BlockSize) // 16
 | ||||
| 	AES256CBCEncrypter := cipher.NewCBCEncrypter(AES256Block, iv) | ||||
| 	cipherText := make([]byte, len(toEncrypt)) | ||||
| 	AES256CBCEncrypter.CryptBlocks(cipherText, toEncrypt) | ||||
| @ -196,12 +196,3 @@ func DecryptKey(ks keyStorePassphrase, keyAddr []byte, auth string) (keyBytes [] | ||||
| 	} | ||||
| 	return keyBytes, keyId, err | ||||
| } | ||||
| 
 | ||||
| func GetEntropyCSPRNG(n int) []byte { | ||||
| 	mainBuff := make([]byte, n) | ||||
| 	_, err := io.ReadFull(crand.Reader, mainBuff) | ||||
| 	if err != nil { | ||||
| 		panic("key generation: reading from crypto/rand failed: " + err.Error()) | ||||
| 	} | ||||
| 	return mainBuff | ||||
| } | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| package crypto | ||||
| 
 | ||||
| import ( | ||||
| 	crand "crypto/rand" | ||||
| 	"github.com/ethereum/go-ethereum/crypto/randentropy" | ||||
| 	"reflect" | ||||
| 	"testing" | ||||
| ) | ||||
| @ -9,7 +9,7 @@ import ( | ||||
| func TestKeyStorePlain(t *testing.T) { | ||||
| 	ks := NewKeyStorePlain(DefaultDataDir()) | ||||
| 	pass := "" // not used but required by API
 | ||||
| 	k1, err := ks.GenerateNewKey(crand.Reader, pass) | ||||
| 	k1, err := ks.GenerateNewKey(randentropy.Reader, pass) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| @ -37,7 +37,7 @@ func TestKeyStorePlain(t *testing.T) { | ||||
| func TestKeyStorePassphrase(t *testing.T) { | ||||
| 	ks := NewKeyStorePassphrase(DefaultDataDir()) | ||||
| 	pass := "foo" | ||||
| 	k1, err := ks.GenerateNewKey(crand.Reader, pass) | ||||
| 	k1, err := ks.GenerateNewKey(randentropy.Reader, pass) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| @ -63,7 +63,7 @@ func TestKeyStorePassphrase(t *testing.T) { | ||||
| func TestKeyStorePassphraseDecryptionFail(t *testing.T) { | ||||
| 	ks := NewKeyStorePassphrase(DefaultDataDir()) | ||||
| 	pass := "foo" | ||||
| 	k1, err := ks.GenerateNewKey(crand.Reader, pass) | ||||
| 	k1, err := ks.GenerateNewKey(randentropy.Reader, pass) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
							
								
								
									
										84
									
								
								crypto/randentropy/rand_entropy.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								crypto/randentropy/rand_entropy.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,84 @@ | ||||
| package randentropy | ||||
| 
 | ||||
| import ( | ||||
| 	crand "crypto/rand" | ||||
| 	"encoding/binary" | ||||
| 	"github.com/ethereum/go-ethereum/crypto/sha3" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| var Reader io.Reader = &randEntropy{} | ||||
| 
 | ||||
| type randEntropy struct { | ||||
| } | ||||
| 
 | ||||
| func (*randEntropy) Read(bytes []byte) (n int, err error) { | ||||
| 	readBytes := GetEntropyMixed(len(bytes)) | ||||
| 	copy(bytes, readBytes) | ||||
| 	return len(bytes), nil | ||||
| } | ||||
| 
 | ||||
| // TODO: copied from crypto.go , move to sha3 package?
 | ||||
| func Sha3(data []byte) []byte { | ||||
| 	d := sha3.NewKeccak256() | ||||
| 	d.Write(data) | ||||
| 
 | ||||
| 	return d.Sum(nil) | ||||
| } | ||||
| 
 | ||||
| // TODO: verify. this needs to be audited
 | ||||
| // we start with crypt/rand, then XOR in additional entropy from OS
 | ||||
| func GetEntropyMixed(n int) []byte { | ||||
| 	startTime := time.Now().UnixNano() | ||||
| 	// for each source, we take SHA3 of the source and use it as seed to math/rand
 | ||||
| 	// then read bytes from it and XOR them onto the bytes read from crypto/rand
 | ||||
| 	mainBuff := GetEntropyCSPRNG(n) | ||||
| 	// 1. OS entropy sources
 | ||||
| 	startTimeBytes := make([]byte, 32) | ||||
| 	binary.PutVarint(startTimeBytes, startTime) | ||||
| 	startTimeHash := Sha3(startTimeBytes) | ||||
| 	mixBytes(mainBuff, startTimeHash) | ||||
| 
 | ||||
| 	pid := os.Getpid() | ||||
| 	pidBytes := make([]byte, 32) | ||||
| 	binary.PutUvarint(pidBytes, uint64(pid)) | ||||
| 	pidHash := Sha3(pidBytes) | ||||
| 	mixBytes(mainBuff, pidHash) | ||||
| 
 | ||||
| 	osEnv := os.Environ() | ||||
| 	osEnvBytes := []byte(strings.Join(osEnv, "")) | ||||
| 	osEnvHash := Sha3(osEnvBytes) | ||||
| 	mixBytes(mainBuff, osEnvHash) | ||||
| 
 | ||||
| 	// not all OS have hostname in env variables
 | ||||
| 	osHostName, err := os.Hostname() | ||||
| 	if err != nil { | ||||
| 		osHostNameBytes := []byte(osHostName) | ||||
| 		osHostNameHash := Sha3(osHostNameBytes) | ||||
| 		mixBytes(mainBuff, osHostNameHash) | ||||
| 	} | ||||
| 	return mainBuff | ||||
| } | ||||
| 
 | ||||
| func GetEntropyCSPRNG(n int) []byte { | ||||
| 	mainBuff := make([]byte, n) | ||||
| 	_, err := io.ReadFull(crand.Reader, mainBuff) | ||||
| 	if err != nil { | ||||
| 		panic("reading from crypto/rand failed: " + err.Error()) | ||||
| 	} | ||||
| 	return mainBuff | ||||
| } | ||||
| 
 | ||||
| func mixBytes(buff []byte, mixBuff []byte) []byte { | ||||
| 	bytesToMix := len(buff) | ||||
| 	if bytesToMix > 32 { | ||||
| 		bytesToMix = 32 | ||||
| 	} | ||||
| 	for i := 0; i < bytesToMix; i++ { | ||||
| 		buff[i] ^= mixBuff[i] | ||||
| 	} | ||||
| 	return buff | ||||
| } | ||||
| @ -15,6 +15,7 @@ import "C" | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"errors" | ||||
| 	"github.com/ethereum/go-ethereum/crypto/randentropy" | ||||
| 	"unsafe" | ||||
| ) | ||||
| 
 | ||||
| @ -68,7 +69,7 @@ func GenerateKeyPair() ([]byte, []byte) { | ||||
| 	const seckey_len = 32 | ||||
| 
 | ||||
| 	var pubkey []byte = make([]byte, pubkey_len) | ||||
| 	var seckey []byte = RandByte(seckey_len) | ||||
| 	var seckey []byte = randentropy.GetEntropyMixed(seckey_len) | ||||
| 
 | ||||
| 	var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0])) | ||||
| 	var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0])) | ||||
| @ -124,7 +125,7 @@ int secp256k1_ecdsa_sign_compact(const unsigned char *msg, int msglen, | ||||
| */ | ||||
| 
 | ||||
| func Sign(msg []byte, seckey []byte) ([]byte, error) { | ||||
| 	nonce := RandByte(32) | ||||
| 	nonce := randentropy.GetEntropyMixed(32) | ||||
| 
 | ||||
| 	var sig []byte = make([]byte, 65) | ||||
| 	var recid C.int | ||||
|  | ||||
| @ -1,97 +0,0 @@ | ||||
| package secp256k1 | ||||
| 
 | ||||
| import ( | ||||
| 	crand "crypto/rand" | ||||
| 	"io" | ||||
| 	mrand "math/rand" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| /* | ||||
| Note: | ||||
| 
 | ||||
| - On windows cryto/rand uses CrytoGenRandom which uses RC4 which is insecure | ||||
| - Android random number generator is known to be insecure. | ||||
| - Linux uses /dev/urandom , which is thought to be secure and uses entropy pool | ||||
| 
 | ||||
| Therefore the output is salted. | ||||
| */ | ||||
| 
 | ||||
| //finalizer from MurmerHash3
 | ||||
| func mmh3f(key uint64) uint64 { | ||||
| 	key ^= key >> 33 | ||||
| 	key *= 0xff51afd7ed558ccd | ||||
| 	key ^= key >> 33 | ||||
| 	key *= 0xc4ceb9fe1a85ec53 | ||||
| 	key ^= key >> 33 | ||||
| 	return key | ||||
| } | ||||
| 
 | ||||
| //knuth hash
 | ||||
| func knuth_hash(in []byte) uint64 { | ||||
| 	var acc uint64 = 3074457345618258791 | ||||
| 	for i := 0; i < len(in); i++ { | ||||
| 		acc += uint64(in[i]) | ||||
| 		acc *= 3074457345618258799 | ||||
| 	} | ||||
| 	return acc | ||||
| } | ||||
| 
 | ||||
| var _rand *mrand.Rand | ||||
| 
 | ||||
| func init() { | ||||
| 	var seed1 uint64 = mmh3f(uint64(time.Now().UnixNano())) | ||||
| 	var seed2 uint64 = knuth_hash([]byte(strings.Join(os.Environ(), ""))) | ||||
| 	var seed3 uint64 = mmh3f(uint64(os.Getpid())) | ||||
| 
 | ||||
| 	_rand = mrand.New(mrand.NewSource(int64(seed1 ^ seed2 ^ seed3))) | ||||
| } | ||||
| 
 | ||||
| func saltByte(n int) []byte { | ||||
| 	buff := make([]byte, n) | ||||
| 	for i := 0; i < len(buff); i++ { | ||||
| 		var v uint64 = uint64(_rand.Int63()) | ||||
| 		var b byte | ||||
| 		for j := 0; j < 8; j++ { | ||||
| 			b ^= byte(v & 0xff) | ||||
| 			v = v >> 8 | ||||
| 		} | ||||
| 		buff[i] = b | ||||
| 	} | ||||
| 	return buff | ||||
| } | ||||
| 
 | ||||
| //On Unix-like systems, Reader reads from /dev/urandom.
 | ||||
| //On Windows systems, Reader uses the CryptGenRandom API.
 | ||||
| 
 | ||||
| //use entropy pool etc and cryptographic random number generator
 | ||||
| //mix in time
 | ||||
| //mix in mix in cpu cycle count
 | ||||
| func RandByte(n int) []byte { | ||||
| 	buff := make([]byte, n) | ||||
| 	ret, err := io.ReadFull(crand.Reader, buff) | ||||
| 	if len(buff) != ret || err != nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	buff2 := saltByte(n) | ||||
| 	for i := 0; i < n; i++ { | ||||
| 		buff[i] ^= buff2[2] | ||||
| 	} | ||||
| 	return buff | ||||
| } | ||||
| 
 | ||||
| /* | ||||
| 	On Unix-like systems, Reader reads from /dev/urandom. | ||||
| 	On Windows systems, Reader uses the CryptGenRandom API. | ||||
| */ | ||||
| func RandByteWeakCrypto(n int) []byte { | ||||
| 	buff := make([]byte, n) | ||||
| 	ret, err := io.ReadFull(crand.Reader, buff) | ||||
| 	if len(buff) != ret || err != nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return buff | ||||
| } | ||||
| @ -3,6 +3,7 @@ package secp256k1 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"github.com/ethereum/go-ethereum/crypto/randentropy" | ||||
| 	"log" | ||||
| 	"testing" | ||||
| ) | ||||
| @ -12,7 +13,7 @@ const SigSize = 65  //64+1 | ||||
| 
 | ||||
| func Test_Secp256_00(t *testing.T) { | ||||
| 
 | ||||
| 	var nonce []byte = RandByte(32) //going to get bitcoins stolen!
 | ||||
| 	var nonce []byte = randentropy.GetEntropyMixed(32) //going to get bitcoins stolen!
 | ||||
| 
 | ||||
| 	if len(nonce) != 32 { | ||||
| 		t.Fatal() | ||||
| @ -50,7 +51,7 @@ func Test_Secp256_01(t *testing.T) { | ||||
| //test size of messages
 | ||||
| func Test_Secp256_02s(t *testing.T) { | ||||
| 	pubkey, seckey := GenerateKeyPair() | ||||
| 	msg := RandByte(32) | ||||
| 	msg := randentropy.GetEntropyMixed(32) | ||||
| 	sig, _ := Sign(msg, seckey) | ||||
| 	CompactSigTest(sig) | ||||
| 	if sig == nil { | ||||
| @ -73,7 +74,7 @@ func Test_Secp256_02s(t *testing.T) { | ||||
| //test signing message
 | ||||
| func Test_Secp256_02(t *testing.T) { | ||||
| 	pubkey1, seckey := GenerateKeyPair() | ||||
| 	msg := RandByte(32) | ||||
| 	msg := randentropy.GetEntropyMixed(32) | ||||
| 	sig, _ := Sign(msg, seckey) | ||||
| 	if sig == nil { | ||||
| 		t.Fatal("Signature nil") | ||||
| @ -96,7 +97,7 @@ func Test_Secp256_02(t *testing.T) { | ||||
| //test pubkey recovery
 | ||||
| func Test_Secp256_02a(t *testing.T) { | ||||
| 	pubkey1, seckey1 := GenerateKeyPair() | ||||
| 	msg := RandByte(32) | ||||
| 	msg := randentropy.GetEntropyMixed(32) | ||||
| 	sig, _ := Sign(msg, seckey1) | ||||
| 
 | ||||
| 	if sig == nil { | ||||
| @ -125,7 +126,7 @@ func Test_Secp256_02a(t *testing.T) { | ||||
| func Test_Secp256_03(t *testing.T) { | ||||
| 	_, seckey := GenerateKeyPair() | ||||
| 	for i := 0; i < TESTS; i++ { | ||||
| 		msg := RandByte(32) | ||||
| 		msg := randentropy.GetEntropyMixed(32) | ||||
| 		sig, _ := Sign(msg, seckey) | ||||
| 		CompactSigTest(sig) | ||||
| 
 | ||||
| @ -141,7 +142,7 @@ func Test_Secp256_03(t *testing.T) { | ||||
| func Test_Secp256_04(t *testing.T) { | ||||
| 	for i := 0; i < TESTS; i++ { | ||||
| 		pubkey1, seckey := GenerateKeyPair() | ||||
| 		msg := RandByte(32) | ||||
| 		msg := randentropy.GetEntropyMixed(32) | ||||
| 		sig, _ := Sign(msg, seckey) | ||||
| 		CompactSigTest(sig) | ||||
| 
 | ||||
| @ -164,7 +165,7 @@ func Test_Secp256_04(t *testing.T) { | ||||
| //	-SIPA look at this
 | ||||
| 
 | ||||
| func randSig() []byte { | ||||
| 	sig := RandByte(65) | ||||
| 	sig := randentropy.GetEntropyMixed(65) | ||||
| 	sig[32] &= 0x70 | ||||
| 	sig[64] %= 4 | ||||
| 	return sig | ||||
| @ -172,7 +173,7 @@ func randSig() []byte { | ||||
| 
 | ||||
| func Test_Secp256_06a_alt0(t *testing.T) { | ||||
| 	pubkey1, seckey := GenerateKeyPair() | ||||
| 	msg := RandByte(32) | ||||
| 	msg := randentropy.GetEntropyMixed(32) | ||||
| 	sig, _ := Sign(msg, seckey) | ||||
| 
 | ||||
| 	if sig == nil { | ||||
| @ -203,12 +204,12 @@ func Test_Secp256_06a_alt0(t *testing.T) { | ||||
| 
 | ||||
| func Test_Secp256_06b(t *testing.T) { | ||||
| 	pubkey1, seckey := GenerateKeyPair() | ||||
| 	msg := RandByte(32) | ||||
| 	msg := randentropy.GetEntropyMixed(32) | ||||
| 	sig, _ := Sign(msg, seckey) | ||||
| 
 | ||||
| 	fail_count := 0 | ||||
| 	for i := 0; i < TESTS; i++ { | ||||
| 		msg = RandByte(32) | ||||
| 		msg = randentropy.GetEntropyMixed(32) | ||||
| 		pubkey2, _ := RecoverPubkey(msg, sig) | ||||
| 		if bytes.Equal(pubkey1, pubkey2) == true { | ||||
| 			t.Fail() | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user