github.com/luckypickle/go-ethereum-vet@v1.14.2/whisper/whisperv6/message.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Contains the Whisper protocol Message element. 18 19 package whisperv6 20 21 import ( 22 "crypto/aes" 23 "crypto/cipher" 24 "crypto/ecdsa" 25 crand "crypto/rand" 26 "encoding/binary" 27 "errors" 28 mrand "math/rand" 29 "strconv" 30 31 "github.com/luckypickle/go-ethereum-vet/common" 32 "github.com/luckypickle/go-ethereum-vet/crypto" 33 "github.com/luckypickle/go-ethereum-vet/crypto/ecies" 34 "github.com/luckypickle/go-ethereum-vet/log" 35 ) 36 37 // MessageParams specifies the exact way a message should be wrapped 38 // into an Envelope. 39 type MessageParams struct { 40 TTL uint32 41 Src *ecdsa.PrivateKey 42 Dst *ecdsa.PublicKey 43 KeySym []byte 44 Topic TopicType 45 WorkTime uint32 46 PoW float64 47 Payload []byte 48 Padding []byte 49 } 50 51 // SentMessage represents an end-user data packet to transmit through the 52 // Whisper protocol. These are wrapped into Envelopes that need not be 53 // understood by intermediate nodes, just forwarded. 54 type sentMessage struct { 55 Raw []byte 56 } 57 58 // ReceivedMessage represents a data packet to be received through the 59 // Whisper protocol and successfully decrypted. 60 type ReceivedMessage struct { 61 Raw []byte 62 63 Payload []byte 64 Padding []byte 65 Signature []byte 66 Salt []byte 67 68 PoW float64 // Proof of work as described in the Whisper spec 69 Sent uint32 // Time when the message was posted into the network 70 TTL uint32 // Maximum time to live allowed for the message 71 Src *ecdsa.PublicKey // Message recipient (identity used to decode the message) 72 Dst *ecdsa.PublicKey // Message recipient (identity used to decode the message) 73 Topic TopicType 74 75 SymKeyHash common.Hash // The Keccak256Hash of the key 76 EnvelopeHash common.Hash // Message envelope hash to act as a unique id 77 } 78 79 func isMessageSigned(flags byte) bool { 80 return (flags & signatureFlag) != 0 81 } 82 83 func (msg *ReceivedMessage) isSymmetricEncryption() bool { 84 return msg.SymKeyHash != common.Hash{} 85 } 86 87 func (msg *ReceivedMessage) isAsymmetricEncryption() bool { 88 return msg.Dst != nil 89 } 90 91 // NewSentMessage creates and initializes a non-signed, non-encrypted Whisper message. 92 func NewSentMessage(params *MessageParams) (*sentMessage, error) { 93 const payloadSizeFieldMaxSize = 4 94 msg := sentMessage{} 95 msg.Raw = make([]byte, 1, 96 flagsLength+payloadSizeFieldMaxSize+len(params.Payload)+len(params.Padding)+signatureLength+padSizeLimit) 97 msg.Raw[0] = 0 // set all the flags to zero 98 msg.addPayloadSizeField(params.Payload) 99 msg.Raw = append(msg.Raw, params.Payload...) 100 err := msg.appendPadding(params) 101 return &msg, err 102 } 103 104 // addPayloadSizeField appends the auxiliary field containing the size of payload 105 func (msg *sentMessage) addPayloadSizeField(payload []byte) { 106 fieldSize := getSizeOfPayloadSizeField(payload) 107 field := make([]byte, 4) 108 binary.LittleEndian.PutUint32(field, uint32(len(payload))) 109 field = field[:fieldSize] 110 msg.Raw = append(msg.Raw, field...) 111 msg.Raw[0] |= byte(fieldSize) 112 } 113 114 // getSizeOfPayloadSizeField returns the number of bytes necessary to encode the size of payload 115 func getSizeOfPayloadSizeField(payload []byte) int { 116 s := 1 117 for i := len(payload); i >= 256; i /= 256 { 118 s++ 119 } 120 return s 121 } 122 123 // appendPadding appends the padding specified in params. 124 // If no padding is provided in params, then random padding is generated. 125 func (msg *sentMessage) appendPadding(params *MessageParams) error { 126 if len(params.Padding) != 0 { 127 // padding data was provided by the Dapp, just use it as is 128 msg.Raw = append(msg.Raw, params.Padding...) 129 return nil 130 } 131 132 rawSize := flagsLength + getSizeOfPayloadSizeField(params.Payload) + len(params.Payload) 133 if params.Src != nil { 134 rawSize += signatureLength 135 } 136 odd := rawSize % padSizeLimit 137 paddingSize := padSizeLimit - odd 138 pad := make([]byte, paddingSize) 139 _, err := crand.Read(pad) 140 if err != nil { 141 return err 142 } 143 if !validateDataIntegrity(pad, paddingSize) { 144 return errors.New("failed to generate random padding of size " + strconv.Itoa(paddingSize)) 145 } 146 msg.Raw = append(msg.Raw, pad...) 147 return nil 148 } 149 150 // sign calculates and sets the cryptographic signature for the message, 151 // also setting the sign flag. 152 func (msg *sentMessage) sign(key *ecdsa.PrivateKey) error { 153 if isMessageSigned(msg.Raw[0]) { 154 // this should not happen, but no reason to panic 155 log.Error("failed to sign the message: already signed") 156 return nil 157 } 158 159 msg.Raw[0] |= signatureFlag // it is important to set this flag before signing 160 hash := crypto.Keccak256(msg.Raw) 161 signature, err := crypto.Sign(hash, key) 162 if err != nil { 163 msg.Raw[0] &= (0xFF ^ signatureFlag) // clear the flag 164 return err 165 } 166 msg.Raw = append(msg.Raw, signature...) 167 return nil 168 } 169 170 // encryptAsymmetric encrypts a message with a public key. 171 func (msg *sentMessage) encryptAsymmetric(key *ecdsa.PublicKey) error { 172 if !ValidatePublicKey(key) { 173 return errors.New("invalid public key provided for asymmetric encryption") 174 } 175 encrypted, err := ecies.Encrypt(crand.Reader, ecies.ImportECDSAPublic(key), msg.Raw, nil, nil) 176 if err == nil { 177 msg.Raw = encrypted 178 } 179 return err 180 } 181 182 // encryptSymmetric encrypts a message with a topic key, using AES-GCM-256. 183 // nonce size should be 12 bytes (see cipher.gcmStandardNonceSize). 184 func (msg *sentMessage) encryptSymmetric(key []byte) (err error) { 185 if !validateDataIntegrity(key, aesKeyLength) { 186 return errors.New("invalid key provided for symmetric encryption, size: " + strconv.Itoa(len(key))) 187 } 188 block, err := aes.NewCipher(key) 189 if err != nil { 190 return err 191 } 192 aesgcm, err := cipher.NewGCM(block) 193 if err != nil { 194 return err 195 } 196 salt, err := generateSecureRandomData(aesNonceLength) // never use more than 2^32 random nonces with a given key 197 if err != nil { 198 return err 199 } 200 encrypted := aesgcm.Seal(nil, salt, msg.Raw, nil) 201 msg.Raw = append(encrypted, salt...) 202 return nil 203 } 204 205 // generateSecureRandomData generates random data where extra security is required. 206 // The purpose of this function is to prevent some bugs in software or in hardware 207 // from delivering not-very-random data. This is especially useful for AES nonce, 208 // where true randomness does not really matter, but it is very important to have 209 // a unique nonce for every message. 210 func generateSecureRandomData(length int) ([]byte, error) { 211 x := make([]byte, length) 212 y := make([]byte, length) 213 res := make([]byte, length) 214 215 _, err := crand.Read(x) 216 if err != nil { 217 return nil, err 218 } else if !validateDataIntegrity(x, length) { 219 return nil, errors.New("crypto/rand failed to generate secure random data") 220 } 221 _, err = mrand.Read(y) 222 if err != nil { 223 return nil, err 224 } else if !validateDataIntegrity(y, length) { 225 return nil, errors.New("math/rand failed to generate secure random data") 226 } 227 for i := 0; i < length; i++ { 228 res[i] = x[i] ^ y[i] 229 } 230 if !validateDataIntegrity(res, length) { 231 return nil, errors.New("failed to generate secure random data") 232 } 233 return res, nil 234 } 235 236 // Wrap bundles the message into an Envelope to transmit over the network. 237 func (msg *sentMessage) Wrap(options *MessageParams) (envelope *Envelope, err error) { 238 if options.TTL == 0 { 239 options.TTL = DefaultTTL 240 } 241 if options.Src != nil { 242 if err = msg.sign(options.Src); err != nil { 243 return nil, err 244 } 245 } 246 if options.Dst != nil { 247 err = msg.encryptAsymmetric(options.Dst) 248 } else if options.KeySym != nil { 249 err = msg.encryptSymmetric(options.KeySym) 250 } else { 251 err = errors.New("unable to encrypt the message: neither symmetric nor assymmetric key provided") 252 } 253 if err != nil { 254 return nil, err 255 } 256 257 envelope = NewEnvelope(options.TTL, options.Topic, msg) 258 if err = envelope.Seal(options); err != nil { 259 return nil, err 260 } 261 return envelope, nil 262 } 263 264 // decryptSymmetric decrypts a message with a topic key, using AES-GCM-256. 265 // nonce size should be 12 bytes (see cipher.gcmStandardNonceSize). 266 func (msg *ReceivedMessage) decryptSymmetric(key []byte) error { 267 // symmetric messages are expected to contain the 12-byte nonce at the end of the payload 268 if len(msg.Raw) < aesNonceLength { 269 return errors.New("missing salt or invalid payload in symmetric message") 270 } 271 salt := msg.Raw[len(msg.Raw)-aesNonceLength:] 272 273 block, err := aes.NewCipher(key) 274 if err != nil { 275 return err 276 } 277 aesgcm, err := cipher.NewGCM(block) 278 if err != nil { 279 return err 280 } 281 decrypted, err := aesgcm.Open(nil, salt, msg.Raw[:len(msg.Raw)-aesNonceLength], nil) 282 if err != nil { 283 return err 284 } 285 msg.Raw = decrypted 286 msg.Salt = salt 287 return nil 288 } 289 290 // decryptAsymmetric decrypts an encrypted payload with a private key. 291 func (msg *ReceivedMessage) decryptAsymmetric(key *ecdsa.PrivateKey) error { 292 decrypted, err := ecies.ImportECDSA(key).Decrypt(msg.Raw, nil, nil) 293 if err == nil { 294 msg.Raw = decrypted 295 } 296 return err 297 } 298 299 // ValidateAndParse checks the message validity and extracts the fields in case of success. 300 func (msg *ReceivedMessage) ValidateAndParse() bool { 301 end := len(msg.Raw) 302 if end < 1 { 303 return false 304 } 305 306 if isMessageSigned(msg.Raw[0]) { 307 end -= signatureLength 308 if end <= 1 { 309 return false 310 } 311 msg.Signature = msg.Raw[end : end+signatureLength] 312 msg.Src = msg.SigToPubKey() 313 if msg.Src == nil { 314 return false 315 } 316 } 317 318 beg := 1 319 payloadSize := 0 320 sizeOfPayloadSizeField := int(msg.Raw[0] & SizeMask) // number of bytes indicating the size of payload 321 if sizeOfPayloadSizeField != 0 { 322 payloadSize = int(bytesToUintLittleEndian(msg.Raw[beg : beg+sizeOfPayloadSizeField])) 323 if payloadSize+1 > end { 324 return false 325 } 326 beg += sizeOfPayloadSizeField 327 msg.Payload = msg.Raw[beg : beg+payloadSize] 328 } 329 330 beg += payloadSize 331 msg.Padding = msg.Raw[beg:end] 332 return true 333 } 334 335 // SigToPubKey returns the public key associated to the message's 336 // signature. 337 func (msg *ReceivedMessage) SigToPubKey() *ecdsa.PublicKey { 338 defer func() { recover() }() // in case of invalid signature 339 340 pub, err := crypto.SigToPub(msg.hash(), msg.Signature) 341 if err != nil { 342 log.Error("failed to recover public key from signature", "err", err) 343 return nil 344 } 345 return pub 346 } 347 348 // hash calculates the SHA3 checksum of the message flags, payload size field, payload and padding. 349 func (msg *ReceivedMessage) hash() []byte { 350 if isMessageSigned(msg.Raw[0]) { 351 sz := len(msg.Raw) - signatureLength 352 return crypto.Keccak256(msg.Raw[:sz]) 353 } 354 return crypto.Keccak256(msg.Raw) 355 }