mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 15:16:43 +00:00
whisper: salt removed from AES encryption
This commit is contained in:
parent
f32b72ca5d
commit
8174fc7390
8 changed files with 34 additions and 88 deletions
|
|
@ -58,8 +58,9 @@ func TestDBKey(t *testing.T) {
|
|||
}
|
||||
|
||||
func generateEnvelope(t *testing.T) *whisper.Envelope {
|
||||
h := crypto.Keccak256Hash([]byte("test sample data"))
|
||||
params := &whisper.MessageParams{
|
||||
KeySym: []byte("test key"),
|
||||
KeySym: h[:],
|
||||
Topic: whisper.TopicType{},
|
||||
Payload: []byte("test payload"),
|
||||
PoW: powRequirement,
|
||||
|
|
|
|||
|
|
@ -28,12 +28,6 @@ func BenchmarkDeriveKeyMaterial(b *testing.B) {
|
|||
}
|
||||
}
|
||||
|
||||
func BenchmarkDeriveOneTimeKey(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
DeriveOneTimeKey([]byte("test value 1"), []byte("test value 2"), 0)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncryptionSym(b *testing.B) {
|
||||
InitSingleTest()
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ const (
|
|||
TopicLength = 4
|
||||
signatureLength = 65
|
||||
aesKeyLength = 32
|
||||
saltLength = 12
|
||||
AESNonceMaxLength = 12
|
||||
keyIdSize = 32
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ type Envelope struct {
|
|||
Expiry uint32
|
||||
TTL uint32
|
||||
Topic TopicType
|
||||
Salt []byte
|
||||
AESNonce []byte
|
||||
Data []byte
|
||||
EnvNonce uint64
|
||||
|
|
@ -50,15 +49,25 @@ type Envelope struct {
|
|||
// Don't access hash directly, use Hash() function instead.
|
||||
}
|
||||
|
||||
// size returns the size of envelope as it is sent (i.e. public fields only)
|
||||
func (e *Envelope) size() int {
|
||||
return 20 + len(e.Version) + len(e.AESNonce) + len(e.Data)
|
||||
}
|
||||
|
||||
// rlpWithoutNonce returns the RLP encoded envelope contents, except the nonce.
|
||||
func (e *Envelope) rlpWithoutNonce() []byte {
|
||||
res, _ := rlp.EncodeToBytes([]interface{}{e.Version, e.Expiry, e.TTL, e.Topic, e.AESNonce, e.Data})
|
||||
return res
|
||||
}
|
||||
|
||||
// NewEnvelope wraps a Whisper message with expiration and destination data
|
||||
// included into an envelope for network forwarding.
|
||||
func NewEnvelope(ttl uint32, topic TopicType, salt []byte, aesNonce []byte, msg *SentMessage) *Envelope {
|
||||
func NewEnvelope(ttl uint32, topic TopicType, aesNonce []byte, msg *SentMessage) *Envelope {
|
||||
env := Envelope{
|
||||
Version: make([]byte, 1),
|
||||
Expiry: uint32(time.Now().Add(time.Second * time.Duration(ttl)).Unix()),
|
||||
TTL: ttl,
|
||||
Topic: topic,
|
||||
Salt: salt,
|
||||
AESNonce: aesNonce,
|
||||
Data: msg.Raw,
|
||||
EnvNonce: 0,
|
||||
|
|
@ -126,10 +135,6 @@ func (e *Envelope) Seal(options *MessageParams) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (e *Envelope) size() int {
|
||||
return len(e.Data) + len(e.Version) + len(e.AESNonce) + len(e.Salt) + 20
|
||||
}
|
||||
|
||||
func (e *Envelope) PoW() float64 {
|
||||
if e.pow == 0 {
|
||||
e.calculatePoW(0)
|
||||
|
|
@ -159,12 +164,6 @@ func (e *Envelope) powToFirstBit(pow float64) int {
|
|||
return int(bits)
|
||||
}
|
||||
|
||||
// rlpWithoutNonce returns the RLP encoded envelope contents, except the nonce.
|
||||
func (e *Envelope) rlpWithoutNonce() []byte {
|
||||
res, _ := rlp.EncodeToBytes([]interface{}{e.Expiry, e.TTL, e.Topic, e.Salt, e.AESNonce, e.Data})
|
||||
return res
|
||||
}
|
||||
|
||||
// Hash returns the SHA3 hash of the envelope, calculating it if not yet done.
|
||||
func (e *Envelope) Hash() common.Hash {
|
||||
if (e.hash == common.Hash{}) {
|
||||
|
|
@ -210,7 +209,7 @@ func (e *Envelope) OpenAsymmetric(key *ecdsa.PrivateKey) (*ReceivedMessage, erro
|
|||
// OpenSymmetric tries to decrypt an envelope, potentially encrypted with a particular key.
|
||||
func (e *Envelope) OpenSymmetric(key []byte) (msg *ReceivedMessage, err error) {
|
||||
msg = &ReceivedMessage{Raw: e.Data}
|
||||
err = msg.decryptSymmetric(key, e.Salt, e.AESNonce)
|
||||
err = msg.decryptSymmetric(key, e.AESNonce)
|
||||
if err != nil {
|
||||
msg = nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ func generateFilter(t *testing.T, symmetric bool) (*Filter, error) {
|
|||
f.Src = &key.PublicKey
|
||||
|
||||
if symmetric {
|
||||
f.KeySym = make([]byte, 12)
|
||||
f.KeySym = make([]byte, aesKeyLength)
|
||||
mrand.Read(f.KeySym)
|
||||
f.SymKeyHash = crypto.Keccak256Hash(f.KeySym)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -23,14 +23,12 @@ import (
|
|||
"crypto/cipher"
|
||||
"crypto/ecdsa"
|
||||
crand "crypto/rand"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/crypto/ecies"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
)
|
||||
|
||||
// Options specifies the exact way a message should be wrapped into an Envelope.
|
||||
|
|
@ -86,15 +84,6 @@ func (msg *ReceivedMessage) isAsymmetricEncryption() bool {
|
|||
return msg.Dst != nil
|
||||
}
|
||||
|
||||
func DeriveOneTimeKey(key []byte, salt []byte, version uint64) ([]byte, error) {
|
||||
if version == 0 {
|
||||
derivedKey := pbkdf2.Key(key, salt, 8, aesKeyLength, sha256.New)
|
||||
return derivedKey, nil
|
||||
} else {
|
||||
return nil, unknownVersionError(version)
|
||||
}
|
||||
}
|
||||
|
||||
// NewMessage creates and initializes a non-signed, non-encrypted Whisper message.
|
||||
func NewSentMessage(params *MessageParams) *SentMessage {
|
||||
msg := SentMessage{}
|
||||
|
|
@ -178,46 +167,31 @@ func (msg *SentMessage) encryptAsymmetric(key *ecdsa.PublicKey) error {
|
|||
|
||||
// encryptSymmetric encrypts a message with a topic key, using AES-GCM-256.
|
||||
// nonce size should be 12 bytes (see cipher.gcmStandardNonceSize).
|
||||
func (msg *SentMessage) encryptSymmetric(key []byte) (salt []byte, nonce []byte, err error) {
|
||||
func (msg *SentMessage) encryptSymmetric(key []byte) (nonce []byte, err error) {
|
||||
if !validateSymmetricKey(key) {
|
||||
return nil, nil, errors.New("invalid key provided for symmetric encryption")
|
||||
return nil, errors.New("invalid key provided for symmetric encryption")
|
||||
}
|
||||
|
||||
salt = make([]byte, saltLength)
|
||||
_, err = crand.Read(salt)
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
} else if !validateSymmetricKey(salt) {
|
||||
return nil, nil, errors.New("crypto/rand failed to generate salt")
|
||||
}
|
||||
|
||||
derivedKey, err := DeriveOneTimeKey(key, salt, EnvelopeVersion)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if !validateSymmetricKey(derivedKey) {
|
||||
return nil, nil, errors.New("failed to derive one-time key")
|
||||
}
|
||||
block, err := aes.NewCipher(derivedKey)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
aesgcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// never use more than 2^32 random nonces with a given key
|
||||
nonce = make([]byte, aesgcm.NonceSize())
|
||||
_, err = crand.Read(nonce)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
} else if !validateSymmetricKey(nonce) {
|
||||
return nil, nil, errors.New("crypto/rand failed to generate nonce")
|
||||
return nil, errors.New("crypto/rand failed to generate nonce")
|
||||
}
|
||||
|
||||
msg.Raw = aesgcm.Seal(nil, nonce, msg.Raw, nil)
|
||||
return salt, nonce, nil
|
||||
return nonce, nil
|
||||
}
|
||||
|
||||
// Wrap bundles the message into an Envelope to transmit over the network.
|
||||
|
|
@ -231,11 +205,11 @@ func (msg *SentMessage) Wrap(options *MessageParams) (envelope *Envelope, err er
|
|||
return nil, err
|
||||
}
|
||||
}
|
||||
var salt, nonce []byte
|
||||
var nonce []byte
|
||||
if options.Dst != nil {
|
||||
err = msg.encryptAsymmetric(options.Dst)
|
||||
} else if options.KeySym != nil {
|
||||
salt, nonce, err = msg.encryptSymmetric(options.KeySym)
|
||||
nonce, err = msg.encryptSymmetric(options.KeySym)
|
||||
} else {
|
||||
err = errors.New("unable to encrypt the message: neither symmetric nor assymmetric key provided")
|
||||
}
|
||||
|
|
@ -244,7 +218,7 @@ func (msg *SentMessage) Wrap(options *MessageParams) (envelope *Envelope, err er
|
|||
return nil, err
|
||||
}
|
||||
|
||||
envelope = NewEnvelope(options.TTL, options.Topic, salt, nonce, msg)
|
||||
envelope = NewEnvelope(options.TTL, options.Topic, nonce, msg)
|
||||
err = envelope.Seal(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -254,13 +228,8 @@ func (msg *SentMessage) Wrap(options *MessageParams) (envelope *Envelope, err er
|
|||
|
||||
// decryptSymmetric decrypts a message with a topic key, using AES-GCM-256.
|
||||
// nonce size should be 12 bytes (see cipher.gcmStandardNonceSize).
|
||||
func (msg *ReceivedMessage) decryptSymmetric(key []byte, salt []byte, nonce []byte) error {
|
||||
derivedKey, err := DeriveOneTimeKey(key, salt, msg.EnvelopeVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(derivedKey)
|
||||
func (msg *ReceivedMessage) decryptSymmetric(key []byte, nonce []byte) error {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -178,11 +178,9 @@ func TestMessageSeal(t *testing.T) {
|
|||
msg := NewSentMessage(params)
|
||||
params.TTL = 1
|
||||
aesnonce := make([]byte, 12)
|
||||
salt := make([]byte, 12)
|
||||
mrand.Read(aesnonce)
|
||||
mrand.Read(salt)
|
||||
|
||||
env := NewEnvelope(params.TTL, params.Topic, salt, aesnonce, msg)
|
||||
env := NewEnvelope(params.TTL, params.Topic, aesnonce, msg)
|
||||
if err != nil {
|
||||
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -262,24 +262,14 @@ func (w *Whisper) GetPrivateKey(id string) (*ecdsa.PrivateKey, error) {
|
|||
// GenerateSymKey generates a random symmetric key and stores it under id,
|
||||
// which is then returned. Will be used in the future for session key exchange.
|
||||
func (w *Whisper) GenerateSymKey() (string, error) {
|
||||
const size = aesKeyLength * 2
|
||||
buf := make([]byte, size)
|
||||
_, err := crand.Read(buf)
|
||||
key := make([]byte, aesKeyLength)
|
||||
_, err := crand.Read(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else if !validateSymmetricKey(buf) {
|
||||
} else if !validateSymmetricKey(key) {
|
||||
return "", fmt.Errorf("error in GenerateSymKey: crypto/rand failed to generate random data")
|
||||
}
|
||||
|
||||
key := buf[:aesKeyLength]
|
||||
salt := buf[aesKeyLength:]
|
||||
derived, err := DeriveOneTimeKey(key, salt, EnvelopeVersion)
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else if !validateSymmetricKey(derived) {
|
||||
return "", fmt.Errorf("failed to derive valid key")
|
||||
}
|
||||
|
||||
id, err := GenerateRandomID()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to generate ID: %s", err)
|
||||
|
|
@ -291,7 +281,7 @@ func (w *Whisper) GenerateSymKey() (string, error) {
|
|||
if w.symKeys[id] != nil {
|
||||
return "", fmt.Errorf("failed to generate unique ID")
|
||||
}
|
||||
w.symKeys[id] = derived
|
||||
w.symKeys[id] = key
|
||||
return id, nil
|
||||
}
|
||||
|
||||
|
|
@ -556,10 +546,6 @@ func (wh *Whisper) add(envelope *Envelope) (bool, error) {
|
|||
return false, fmt.Errorf("oversized AESNonce [%x]", envelope.Hash())
|
||||
}
|
||||
|
||||
if len(envelope.Salt) > saltLength {
|
||||
return false, fmt.Errorf("oversized salt [%x]", envelope.Hash())
|
||||
}
|
||||
|
||||
if envelope.PoW() < wh.minPoW {
|
||||
log.Debug("envelope with low PoW dropped", "PoW", envelope.PoW(), "hash", envelope.Hash().Hex())
|
||||
return false, nil // drop envelope without error
|
||||
|
|
|
|||
Loading…
Reference in a new issue