github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/whisper/whisperv6/message.go (about) 1 // Copyright 2016 The Spectrum Authors 2 // This file is part of the Spectrum library. 3 // 4 // The Spectrum 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 Spectrum 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 Spectrum 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 "strconv" 29 30 "github.com/SmartMeshFoundation/Spectrum/common" 31 "github.com/SmartMeshFoundation/Spectrum/crypto" 32 "github.com/SmartMeshFoundation/Spectrum/crypto/ecies" 33 "github.com/SmartMeshFoundation/Spectrum/log" 34 ) 35 36 // Options specifies the exact way a message should be wrapped into an Envelope. 37 type MessageParams struct { 38 TTL uint32 39 Src *ecdsa.PrivateKey 40 Dst *ecdsa.PublicKey 41 KeySym []byte 42 Topic TopicType 43 WorkTime uint32 44 PoW float64 45 Payload []byte 46 Padding []byte 47 } 48 49 // SentMessage represents an end-user data packet to transmit through the 50 // Whisper protocol. These are wrapped into Envelopes that need not be 51 // understood by intermediate nodes, just forwarded. 52 type sentMessage struct { 53 Raw []byte 54 } 55 56 // ReceivedMessage represents a data packet to be received through the 57 // Whisper protocol. 58 type ReceivedMessage struct { 59 Raw []byte 60 61 Payload []byte 62 Padding []byte 63 Signature []byte 64 Salt []byte 65 66 PoW float64 // Proof of work as described in the Whisper spec 67 Sent uint32 // Time when the message was posted into the network 68 TTL uint32 // Maximum time to live allowed for the message 69 Src *ecdsa.PublicKey // Message recipient (identity used to decode the message) 70 Dst *ecdsa.PublicKey // Message recipient (identity used to decode the message) 71 Topic TopicType 72 73 SymKeyHash common.Hash // The Keccak256Hash of the key, associated with the Topic 74 EnvelopeHash common.Hash // Message envelope hash to act as a unique id 75 } 76 77 func isMessageSigned(flags byte) bool { 78 return (flags & signatureFlag) != 0 79 } 80 81 func (msg *ReceivedMessage) isSymmetricEncryption() bool { 82 return msg.SymKeyHash != common.Hash{} 83 } 84 85 func (msg *ReceivedMessage) isAsymmetricEncryption() bool { 86 return msg.Dst != nil 87 } 88 89 // NewMessage creates and initializes a non-signed, non-encrypted Whisper message. 90 func NewSentMessage(params *MessageParams) (*sentMessage, error) { 91 msg := sentMessage{} 92 msg.Raw = make([]byte, 1, len(params.Payload)+len(params.Padding)+signatureLength+padSizeLimit) 93 msg.Raw[0] = 0 // set all the flags to zero 94 err := msg.appendPadding(params) 95 if err != nil { 96 return nil, err 97 } 98 msg.Raw = append(msg.Raw, params.Payload...) 99 return &msg, nil 100 } 101 102 // getSizeOfLength returns the number of bytes necessary to encode the entire size padding (including these bytes) 103 func getSizeOfLength(b []byte) (sz int, err error) { 104 sz = intSize(len(b)) // first iteration 105 sz = intSize(len(b) + sz) // second iteration 106 if sz > 3 { 107 err = errors.New("oversized padding parameter") 108 } 109 return sz, err 110 } 111 112 // sizeOfIntSize returns minimal number of bytes necessary to encode an integer value 113 func intSize(i int) (s int) { 114 for s = 1; i >= 256; s++ { 115 i /= 256 116 } 117 return s 118 } 119 120 // appendPadding appends the pseudorandom padding bytes and sets the padding flag. 121 // The last byte contains the size of padding (thus, its size must not exceed 256). 122 func (msg *sentMessage) appendPadding(params *MessageParams) error { 123 rawSize := len(params.Payload) + 1 124 if params.Src != nil { 125 rawSize += signatureLength 126 } 127 128 if params.KeySym != nil { 129 rawSize += AESNonceLength 130 } 131 odd := rawSize % padSizeLimit 132 133 if len(params.Padding) != 0 { 134 padSize := len(params.Padding) 135 padLengthSize, err := getSizeOfLength(params.Padding) 136 if err != nil { 137 return err 138 } 139 totalPadSize := padSize + padLengthSize 140 buf := make([]byte, 8) 141 binary.LittleEndian.PutUint32(buf, uint32(totalPadSize)) 142 buf = buf[:padLengthSize] 143 msg.Raw = append(msg.Raw, buf...) 144 msg.Raw = append(msg.Raw, params.Padding...) 145 msg.Raw[0] |= byte(padLengthSize) // number of bytes indicating the padding size 146 } else if odd != 0 { 147 totalPadSize := padSizeLimit - odd 148 if totalPadSize > 255 { 149 // this algorithm is only valid if padSizeLimit < 256. 150 // if padSizeLimit will ever change, please fix the algorithm 151 // (please see also ReceivedMessage.extractPadding() function). 152 panic("please fix the padding algorithm before releasing new version") 153 } 154 buf := make([]byte, totalPadSize) 155 _, err := crand.Read(buf[1:]) 156 if err != nil { 157 return err 158 } 159 if totalPadSize > 6 && !validateSymmetricKey(buf) { 160 return errors.New("failed to generate random padding of size " + strconv.Itoa(totalPadSize)) 161 } 162 buf[0] = byte(totalPadSize) 163 msg.Raw = append(msg.Raw, buf...) 164 msg.Raw[0] |= byte(0x1) // number of bytes indicating the padding size 165 } 166 return nil 167 } 168 169 // sign calculates and sets the cryptographic signature for the message, 170 // also setting the sign flag. 171 func (msg *sentMessage) sign(key *ecdsa.PrivateKey) error { 172 if isMessageSigned(msg.Raw[0]) { 173 // this should not happen, but no reason to panic 174 log.Error("failed to sign the message: already signed") 175 return nil 176 } 177 178 msg.Raw[0] |= signatureFlag 179 hash := crypto.Keccak256(msg.Raw) 180 signature, err := crypto.Sign(hash, key) 181 if err != nil { 182 msg.Raw[0] &= ^signatureFlag // clear the flag 183 return err 184 } 185 msg.Raw = append(msg.Raw, signature...) 186 return nil 187 } 188 189 // encryptAsymmetric encrypts a message with a public key. 190 func (msg *sentMessage) encryptAsymmetric(key *ecdsa.PublicKey) error { 191 if !ValidatePublicKey(key) { 192 return errors.New("invalid public key provided for asymmetric encryption") 193 } 194 encrypted, err := ecies.Encrypt(crand.Reader, ecies.ImportECDSAPublic(key), msg.Raw, nil, nil) 195 if err == nil { 196 msg.Raw = encrypted 197 } 198 return err 199 } 200 201 // encryptSymmetric encrypts a message with a topic key, using AES-GCM-256. 202 // nonce size should be 12 bytes (see cipher.gcmStandardNonceSize). 203 func (msg *sentMessage) encryptSymmetric(key []byte) (err error) { 204 if !validateSymmetricKey(key) { 205 return errors.New("invalid key provided for symmetric encryption") 206 } 207 208 block, err := aes.NewCipher(key) 209 if err != nil { 210 return err 211 } 212 aesgcm, err := cipher.NewGCM(block) 213 if err != nil { 214 return err 215 } 216 217 // never use more than 2^32 random nonces with a given key 218 salt := make([]byte, aesgcm.NonceSize()) 219 _, err = crand.Read(salt) 220 if err != nil { 221 return err 222 } else if !validateSymmetricKey(salt) { 223 return errors.New("crypto/rand failed to generate salt") 224 } 225 226 msg.Raw = append(aesgcm.Seal(nil, salt, msg.Raw, nil), salt...) 227 return nil 228 } 229 230 // Wrap bundles the message into an Envelope to transmit over the network. 231 func (msg *sentMessage) Wrap(options *MessageParams) (envelope *Envelope, err error) { 232 if options.TTL == 0 { 233 options.TTL = DefaultTTL 234 } 235 if options.Src != nil { 236 if err = msg.sign(options.Src); err != nil { 237 return nil, err 238 } 239 } 240 if options.Dst != nil { 241 err = msg.encryptAsymmetric(options.Dst) 242 } else if options.KeySym != nil { 243 err = msg.encryptSymmetric(options.KeySym) 244 } else { 245 err = errors.New("unable to encrypt the message: neither symmetric nor assymmetric key provided") 246 } 247 if err != nil { 248 return nil, err 249 } 250 251 envelope = NewEnvelope(options.TTL, options.Topic, msg) 252 if err = envelope.Seal(options); err != nil { 253 return nil, err 254 } 255 return envelope, nil 256 } 257 258 // decryptSymmetric decrypts a message with a topic key, using AES-GCM-256. 259 // nonce size should be 12 bytes (see cipher.gcmStandardNonceSize). 260 func (msg *ReceivedMessage) decryptSymmetric(key []byte) error { 261 // In v6, symmetric messages are expected to contain the 12-byte 262 // "salt" at the end of the payload. 263 if len(msg.Raw) < AESNonceLength { 264 return errors.New("missing salt or invalid payload in symmetric message") 265 } 266 salt := msg.Raw[len(msg.Raw)-AESNonceLength:] 267 268 block, err := aes.NewCipher(key) 269 if err != nil { 270 return err 271 } 272 aesgcm, err := cipher.NewGCM(block) 273 if err != nil { 274 return err 275 } 276 if len(salt) != aesgcm.NonceSize() { 277 log.Error("decrypting the message", "AES salt size", len(salt)) 278 return errors.New("wrong AES salt size") 279 } 280 decrypted, err := aesgcm.Open(nil, salt, msg.Raw[:len(msg.Raw)-AESNonceLength], nil) 281 if err != nil { 282 return err 283 } 284 msg.Raw = decrypted 285 msg.Salt = salt 286 return nil 287 } 288 289 // decryptAsymmetric decrypts an encrypted payload with a private key. 290 func (msg *ReceivedMessage) decryptAsymmetric(key *ecdsa.PrivateKey) error { 291 decrypted, err := ecies.ImportECDSA(key).Decrypt(crand.Reader, msg.Raw, nil, nil) 292 if err == nil { 293 msg.Raw = decrypted 294 } 295 return err 296 } 297 298 // Validate checks the validity and extracts the fields in case of success 299 func (msg *ReceivedMessage) Validate() bool { 300 end := len(msg.Raw) 301 if end < 1 { 302 return false 303 } 304 305 if isMessageSigned(msg.Raw[0]) { 306 end -= signatureLength 307 if end <= 1 { 308 return false 309 } 310 msg.Signature = msg.Raw[end:] 311 msg.Src = msg.SigToPubKey() 312 if msg.Src == nil { 313 return false 314 } 315 } 316 317 padSize, ok := msg.extractPadding(end) 318 if !ok { 319 return false 320 } 321 322 msg.Payload = msg.Raw[1+padSize : end] 323 return true 324 } 325 326 // extractPadding extracts the padding from raw message. 327 // although we don't support sending messages with padding size 328 // exceeding 255 bytes, such messages are perfectly valid, and 329 // can be successfully decrypted. 330 func (msg *ReceivedMessage) extractPadding(end int) (int, bool) { 331 paddingSize := 0 332 sz := int(msg.Raw[0] & paddingMask) // number of bytes indicating the entire size of padding (including these bytes) 333 // could be zero -- it means no padding 334 if sz != 0 { 335 paddingSize = int(bytesToUintLittleEndian(msg.Raw[1 : 1+sz])) 336 if paddingSize < sz || paddingSize+1 > end { 337 return 0, false 338 } 339 msg.Padding = msg.Raw[1+sz : 1+paddingSize] 340 } 341 return paddingSize, true 342 } 343 344 // Recover retrieves the public key of the message signer. 345 func (msg *ReceivedMessage) SigToPubKey() *ecdsa.PublicKey { 346 defer func() { recover() }() // in case of invalid signature 347 348 pub, err := crypto.SigToPub(msg.hash(), msg.Signature) 349 if err != nil { 350 log.Error("failed to recover public key from signature", "err", err) 351 return nil 352 } 353 return pub 354 } 355 356 // hash calculates the SHA3 checksum of the message flags, payload and padding. 357 func (msg *ReceivedMessage) hash() []byte { 358 if isMessageSigned(msg.Raw[0]) { 359 sz := len(msg.Raw) - signatureLength 360 return crypto.Keccak256(msg.Raw[:sz]) 361 } 362 return crypto.Keccak256(msg.Raw) 363 }