mirror of
https://github.com/fluencelabs/tendermint
synced 2025-04-25 06:42:16 +00:00
parent
35b671214c
commit
b1e7fac787
@ -38,6 +38,7 @@ IMPROVEMENTS:
|
|||||||
- [consensus] [\#2169](https://github.com/cosmos/cosmos-sdk/issues/2169) add additional metrics
|
- [consensus] [\#2169](https://github.com/cosmos/cosmos-sdk/issues/2169) add additional metrics
|
||||||
- [p2p] [\#2169](https://github.com/cosmos/cosmos-sdk/issues/2169) add additional metrics
|
- [p2p] [\#2169](https://github.com/cosmos/cosmos-sdk/issues/2169) add additional metrics
|
||||||
- [config] \#2232 added ValidateBasic method, which performs basic checks
|
- [config] \#2232 added ValidateBasic method, which performs basic checks
|
||||||
|
- [crypto] \#2099 make crypto random use chacha, and have forward secrecy of generated randomness
|
||||||
|
|
||||||
BUG FIXES:
|
BUG FIXES:
|
||||||
- [autofile] \#2428 Group.RotateFile need call Flush() before rename (@goolAdapter)
|
- [autofile] \#2428 Group.RotateFile need call Flush() before rename (@goolAdapter)
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package crypto
|
package crypto
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/aes"
|
|
||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
crand "crypto/rand"
|
crand "crypto/rand"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
@ -9,9 +8,17 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/chacha20poly1305"
|
||||||
|
|
||||||
. "github.com/tendermint/tendermint/libs/common"
|
. "github.com/tendermint/tendermint/libs/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// The randomness here is derived from xoring a chacha20 keystream with
|
||||||
|
// output from crypto/rand's OS Entropy Reader. (Due to fears of the OS'
|
||||||
|
// entropy being backdoored)
|
||||||
|
//
|
||||||
|
// For forward secrecy of produced randomness, the internal chacha key is hashed
|
||||||
|
// and thereby rotated after each call.
|
||||||
var gRandInfo *randInfo
|
var gRandInfo *randInfo
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -62,9 +69,8 @@ func CReader() io.Reader {
|
|||||||
|
|
||||||
type randInfo struct {
|
type randInfo struct {
|
||||||
mtx sync.Mutex
|
mtx sync.Mutex
|
||||||
seedBytes [32]byte
|
seedBytes [chacha20poly1305.KeySize]byte
|
||||||
cipherAES256 cipher.Block
|
chacha cipher.AEAD
|
||||||
streamAES256 cipher.Stream
|
|
||||||
reader io.Reader
|
reader io.Reader
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,30 +85,35 @@ func (ri *randInfo) MixEntropy(seedBytes []byte) {
|
|||||||
h.Write(seedBytes)
|
h.Write(seedBytes)
|
||||||
h.Write(ri.seedBytes[:])
|
h.Write(ri.seedBytes[:])
|
||||||
hashBytes := h.Sum(nil)
|
hashBytes := h.Sum(nil)
|
||||||
hashBytes32 := [32]byte{}
|
copy(ri.seedBytes[:], hashBytes)
|
||||||
copy(hashBytes32[:], hashBytes)
|
chacha, err := chacha20poly1305.New(ri.seedBytes[:])
|
||||||
ri.seedBytes = xorBytes32(ri.seedBytes, hashBytes32)
|
|
||||||
// Create new cipher.Block
|
|
||||||
var err error
|
|
||||||
ri.cipherAES256, err = aes.NewCipher(ri.seedBytes[:])
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
PanicSanity("Error creating AES256 cipher: " + err.Error())
|
panic("Initializing chacha20 failed")
|
||||||
}
|
}
|
||||||
// Create new stream
|
ri.chacha = chacha
|
||||||
ri.streamAES256 = cipher.NewCTR(ri.cipherAES256, randBytes(aes.BlockSize))
|
|
||||||
// Create new reader
|
// Create new reader
|
||||||
ri.reader = &cipher.StreamReader{S: ri.streamAES256, R: crand.Reader}
|
ri.reader = &cipher.StreamReader{S: ri, R: crand.Reader}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ri *randInfo) XORKeyStream(dst, src []byte) {
|
||||||
|
// nonce being 0 is safe due to never re-using a key.
|
||||||
|
emptyNonce := make([]byte, 12)
|
||||||
|
tmpDst := ri.chacha.Seal([]byte{}, emptyNonce, src, []byte{0})
|
||||||
|
// this removes the poly1305 tag as well, since chacha is a stream cipher
|
||||||
|
// and we truncate at input length.
|
||||||
|
copy(dst, tmpDst[:len(src)])
|
||||||
|
// hash seedBytes for forward secrecy, and initialize new chacha instance
|
||||||
|
newSeed := sha256.Sum256(ri.seedBytes[:])
|
||||||
|
chacha, err := chacha20poly1305.New(newSeed[:])
|
||||||
|
if err != nil {
|
||||||
|
panic("Initializing chacha20 failed")
|
||||||
|
}
|
||||||
|
ri.chacha = chacha
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ri *randInfo) Read(b []byte) (n int, err error) {
|
func (ri *randInfo) Read(b []byte) (n int, err error) {
|
||||||
ri.mtx.Lock()
|
ri.mtx.Lock()
|
||||||
defer ri.mtx.Unlock()
|
n, err = ri.reader.Read(b)
|
||||||
return ri.reader.Read(b)
|
ri.mtx.Unlock()
|
||||||
}
|
return
|
||||||
|
|
||||||
func xorBytes32(bytesA [32]byte, bytesB [32]byte) (res [32]byte) {
|
|
||||||
for i, b := range bytesA {
|
|
||||||
res[i] = b ^ bytesB[i]
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
}
|
||||||
|
23
crypto/random_test.go
Normal file
23
crypto/random_test.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package crypto_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/tendermint/tendermint/crypto"
|
||||||
|
)
|
||||||
|
|
||||||
|
// the purpose of this test is primarily to ensure that the randomness
|
||||||
|
// generation won't error.
|
||||||
|
func TestRandomConsistency(t *testing.T) {
|
||||||
|
x1 := crypto.CRandBytes(256)
|
||||||
|
x2 := crypto.CRandBytes(256)
|
||||||
|
x3 := crypto.CRandBytes(256)
|
||||||
|
x4 := crypto.CRandBytes(256)
|
||||||
|
x5 := crypto.CRandBytes(256)
|
||||||
|
require.NotEqual(t, x1, x2)
|
||||||
|
require.NotEqual(t, x3, x4)
|
||||||
|
require.NotEqual(t, x4, x5)
|
||||||
|
require.NotEqual(t, x1, x5)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user