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