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