mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 15:16:43 +00:00
whisper: padding format updated
This commit is contained in:
parent
8174fc7390
commit
631da856a5
4 changed files with 88 additions and 33 deletions
|
|
@ -52,14 +52,13 @@ const (
|
||||||
TopicLength = 4
|
TopicLength = 4
|
||||||
signatureLength = 65
|
signatureLength = 65
|
||||||
aesKeyLength = 32
|
aesKeyLength = 32
|
||||||
AESNonceMaxLength = 12
|
AESNonceLength = 12
|
||||||
keyIdSize = 32
|
keyIdSize = 32
|
||||||
|
|
||||||
DefaultMaxMessageLength = 1024 * 1024
|
DefaultMaxMessageLength = 1024 * 1024
|
||||||
DefaultMinimumPoW = 1.0 // todo: review after testing.
|
DefaultMinimumPoW = 1.0 // todo: review after testing.
|
||||||
|
|
||||||
padSizeLimitLower = 128 // it can not be less - we don't want to reveal the absence of signature
|
padSizeLimit = 256 // just an arbitrary number, could be changed without breaking the protocol (must not exceed 2^24)
|
||||||
padSizeLimitUpper = 256 // just an arbitrary number, could be changed without losing compatibility
|
|
||||||
messageQueueLimit = 1024
|
messageQueueLimit = 1024
|
||||||
|
|
||||||
expirationCycle = time.Second
|
expirationCycle = time.Second
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
crand "crypto/rand"
|
crand "crypto/rand"
|
||||||
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
@ -87,7 +88,7 @@ func (msg *ReceivedMessage) isAsymmetricEncryption() bool {
|
||||||
// NewMessage creates and initializes a non-signed, non-encrypted Whisper message.
|
// NewMessage creates and initializes a non-signed, non-encrypted Whisper message.
|
||||||
func NewSentMessage(params *MessageParams) *SentMessage {
|
func NewSentMessage(params *MessageParams) *SentMessage {
|
||||||
msg := SentMessage{}
|
msg := SentMessage{}
|
||||||
msg.Raw = make([]byte, 1, len(params.Payload)+len(params.Payload)+signatureLength+padSizeLimitUpper)
|
msg.Raw = make([]byte, 1, len(params.Payload)+len(params.Payload)+signatureLength+padSizeLimit)
|
||||||
msg.Raw[0] = 0 // set all the flags to zero
|
msg.Raw[0] = 0 // set all the flags to zero
|
||||||
err := msg.appendPadding(params)
|
err := msg.appendPadding(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -98,35 +99,77 @@ func NewSentMessage(params *MessageParams) *SentMessage {
|
||||||
return &msg
|
return &msg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getSizeOfLength returns the number of bytes necessary to encode the entire size padding (including these bytes)
|
||||||
|
func getSizeOfLength(b []byte) (int, error) {
|
||||||
|
// prefer clarity over efficiency
|
||||||
|
var sizeOfLength int
|
||||||
|
len := len(b)
|
||||||
|
|
||||||
|
// first iteration
|
||||||
|
if len < 256 {
|
||||||
|
sizeOfLength = 1
|
||||||
|
} else if len < 256*256 {
|
||||||
|
sizeOfLength = 2
|
||||||
|
} else if len < 256*256*256 {
|
||||||
|
sizeOfLength = 3
|
||||||
|
} else {
|
||||||
|
return 0, errors.New("oversized padding parameter")
|
||||||
|
}
|
||||||
|
|
||||||
|
// second iteration
|
||||||
|
total := len + sizeOfLength
|
||||||
|
if total < 256 {
|
||||||
|
sizeOfLength = 1
|
||||||
|
} else if total < 256*256 {
|
||||||
|
sizeOfLength = 2
|
||||||
|
} else if total < 256*256*256 {
|
||||||
|
sizeOfLength = 3
|
||||||
|
} else {
|
||||||
|
return 0, errors.New("oversized padding parameter")
|
||||||
|
}
|
||||||
|
|
||||||
|
return sizeOfLength, nil
|
||||||
|
}
|
||||||
|
|
||||||
// appendPadding appends the pseudorandom padding bytes and sets the padding flag.
|
// appendPadding appends the pseudorandom padding bytes and sets the padding flag.
|
||||||
// The last byte contains the size of padding (thus, its size must not exceed 256).
|
// The last byte contains the size of padding (thus, its size must not exceed 256).
|
||||||
func (msg *SentMessage) appendPadding(params *MessageParams) error {
|
func (msg *SentMessage) appendPadding(params *MessageParams) error {
|
||||||
total := len(params.Payload) + 1
|
rawSize := len(params.Payload) + 1
|
||||||
if params.Src != nil {
|
if params.Src != nil {
|
||||||
total += signatureLength
|
rawSize += signatureLength
|
||||||
}
|
}
|
||||||
padChunk := padSizeLimitUpper
|
odd := rawSize % padSizeLimit
|
||||||
if total <= padSizeLimitLower {
|
|
||||||
padChunk = padSizeLimitLower
|
if len(params.Padding) != 0 {
|
||||||
|
padSize := len(params.Padding)
|
||||||
|
padLengthSize, err := getSizeOfLength(params.Padding)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
odd := total % padChunk
|
totalPadSize := padSize + padLengthSize
|
||||||
if odd > 0 {
|
buf := make([]byte, 8)
|
||||||
padSize := padChunk - odd
|
binary.LittleEndian.PutUint32(buf, uint32(totalPadSize))
|
||||||
if padSize > 255 {
|
buf = buf[:padLengthSize]
|
||||||
// this algorithm is only valid if padSizeLimitUpper <= 256.
|
msg.Raw = append(msg.Raw, buf...)
|
||||||
// if padSizeLimitUpper will ever change, please fix the algorithm
|
msg.Raw = append(msg.Raw, params.Padding...)
|
||||||
// (for more information see ReceivedMessage.extractPadding() function).
|
msg.Raw[0] |= byte(padLengthSize) // number of bytes indicating the padding size
|
||||||
|
} else if odd != 0 {
|
||||||
|
totalPadSize := padSizeLimit - odd
|
||||||
|
if totalPadSize > 255 {
|
||||||
|
// this algorithm is only valid if padSizeLimit < 256.
|
||||||
|
// if padSizeLimit will ever change, please fix the algorithm
|
||||||
|
// (please see also ReceivedMessage.extractPadding() function).
|
||||||
panic("please fix the padding algorithm before releasing new version")
|
panic("please fix the padding algorithm before releasing new version")
|
||||||
}
|
}
|
||||||
buf := make([]byte, padSize)
|
buf := make([]byte, totalPadSize)
|
||||||
_, err := crand.Read(buf[1:])
|
_, err := crand.Read(buf[1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
buf[0] = byte(padSize)
|
if !validateSymmetricKey(buf) {
|
||||||
if params.Padding != nil {
|
return errors.New("failed to generate random padding")
|
||||||
copy(buf[1:], params.Padding)
|
|
||||||
}
|
}
|
||||||
|
buf[0] = byte(totalPadSize)
|
||||||
msg.Raw = append(msg.Raw, buf...)
|
msg.Raw = append(msg.Raw, buf...)
|
||||||
msg.Raw[0] |= byte(0x1) // number of bytes indicating the padding size
|
msg.Raw[0] |= byte(0x1) // number of bytes indicating the padding size
|
||||||
}
|
}
|
||||||
|
|
@ -292,7 +335,8 @@ func (msg *ReceivedMessage) Validate() bool {
|
||||||
// can be successfully decrypted.
|
// can be successfully decrypted.
|
||||||
func (msg *ReceivedMessage) extractPadding(end int) (int, bool) {
|
func (msg *ReceivedMessage) extractPadding(end int) (int, bool) {
|
||||||
paddingSize := 0
|
paddingSize := 0
|
||||||
sz := int(msg.Raw[0] & paddingMask) // number of bytes containing the entire size of padding, could be zero
|
sz := int(msg.Raw[0] & paddingMask) // number of bytes indicating the entire size of padding (including these bytes)
|
||||||
|
// could be zero -- it means no padding
|
||||||
if sz != 0 {
|
if sz != 0 {
|
||||||
paddingSize = int(bytesToUintLittleEndian(msg.Raw[1 : 1+sz]))
|
paddingSize = int(bytesToUintLittleEndian(msg.Raw[1 : 1+sz]))
|
||||||
if paddingSize < sz || paddingSize+1 > end {
|
if paddingSize < sz || paddingSize+1 > end {
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ func generateMessageParams() (*MessageParams, error) {
|
||||||
p.WorkTime = 1
|
p.WorkTime = 1
|
||||||
p.TTL = uint32(mrand.Intn(1024))
|
p.TTL = uint32(mrand.Intn(1024))
|
||||||
p.Payload = make([]byte, sz)
|
p.Payload = make([]byte, sz)
|
||||||
p.Padding = make([]byte, padSizeLimitUpper)
|
p.Padding = make([]byte, padSizeLimit)
|
||||||
p.KeySym = make([]byte, aesKeyLength)
|
p.KeySym = make([]byte, aesKeyLength)
|
||||||
|
|
||||||
var b int
|
var b int
|
||||||
|
|
@ -289,21 +289,29 @@ func TestEncryptWithZeroKey(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
|
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := NewSentMessage(params)
|
msg := NewSentMessage(params)
|
||||||
|
|
||||||
params.KeySym = make([]byte, aesKeyLength)
|
params.KeySym = make([]byte, aesKeyLength)
|
||||||
_, err = msg.Wrap(params)
|
_, err = msg.Wrap(params)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("wrapped with zero key, seed: %d.", seed)
|
t.Fatalf("wrapped with zero key, seed: %d.", seed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
params, err = generateMessageParams()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
|
||||||
|
}
|
||||||
|
msg = NewSentMessage(params)
|
||||||
params.KeySym = make([]byte, 0)
|
params.KeySym = make([]byte, 0)
|
||||||
_, err = msg.Wrap(params)
|
_, err = msg.Wrap(params)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("wrapped with empty key, seed: %d.", seed)
|
t.Fatalf("wrapped with empty key, seed: %d.", seed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
params, err = generateMessageParams()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
|
||||||
|
}
|
||||||
|
msg = NewSentMessage(params)
|
||||||
params.KeySym = nil
|
params.KeySym = nil
|
||||||
_, err = msg.Wrap(params)
|
_, err = msg.Wrap(params)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|
|
||||||
|
|
@ -385,6 +385,9 @@ func (w *Whisper) Unsubscribe(id string) error {
|
||||||
// network in the coming cycles.
|
// network in the coming cycles.
|
||||||
func (w *Whisper) Send(envelope *Envelope) error {
|
func (w *Whisper) Send(envelope *Envelope) error {
|
||||||
ok, err := w.add(envelope)
|
ok, err := w.add(envelope)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("failed to add envelope")
|
return fmt.Errorf("failed to add envelope")
|
||||||
}
|
}
|
||||||
|
|
@ -540,10 +543,11 @@ func (wh *Whisper) add(envelope *Envelope) (bool, error) {
|
||||||
return false, fmt.Errorf("oversized version [%x]", envelope.Hash())
|
return false, fmt.Errorf("oversized version [%x]", envelope.Hash())
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(envelope.AESNonce) > AESNonceMaxLength {
|
aesNonceSize := len(envelope.AESNonce)
|
||||||
// the standard AES GSM nonce size is 12,
|
if aesNonceSize != 0 && aesNonceSize != AESNonceLength {
|
||||||
// but const gcmStandardNonceSize cannot be accessed directly
|
// the standard AES GCM nonce size is 12 bytes,
|
||||||
return false, fmt.Errorf("oversized AESNonce [%x]", envelope.Hash())
|
// but constant gcmStandardNonceSize cannot be accessed (not exported)
|
||||||
|
return false, fmt.Errorf("wrong size of AESNonce: %d bytes [env: %x]", aesNonceSize, envelope.Hash())
|
||||||
}
|
}
|
||||||
|
|
||||||
if envelope.PoW() < wh.minPoW {
|
if envelope.PoW() < wh.minPoW {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue