github.com/digdeepmining/go-atheios@v1.5.13-0.20180902133602-d5687a2e6f43/whisper/whisperv5/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 whisperv5 20 21 import ( 22 "crypto/aes" 23 "crypto/cipher" 24 "crypto/ecdsa" 25 crand "crypto/rand" 26 "crypto/sha256" 27 "errors" 28 "fmt" 29 mrand "math/rand" 30 31 "github.com/atheioschain/go-atheios/common" 32 "github.com/atheioschain/go-atheios/crypto" 33 "github.com/atheioschain/go-atheios/logger" 34 "github.com/atheioschain/go-atheios/logger/glog" 35 "golang.org/x/crypto/pbkdf2" 36 ) 37 38 // Options specifies the exact way a message should be wrapped 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. 60 type ReceivedMessage struct { 61 Raw []byte 62 63 Payload []byte 64 Padding []byte 65 Signature []byte 66 67 PoW float64 // Proof of work as described in the Whisper spec 68 Sent uint32 // Time when the message was posted into the network 69 TTL uint32 // Maximum time to live allowed for the message 70 Src *ecdsa.PublicKey // Message recipient (identity used to decode the message) 71 Dst *ecdsa.PublicKey // Message recipient (identity used to decode the message) 72 Topic TopicType 73 74 SymKeyHash common.Hash // The Keccak256Hash of the key, associated with the Topic 75 EnvelopeHash common.Hash // Message envelope hash to act as a unique id 76 EnvelopeVersion uint64 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 func DeriveOneTimeKey(key []byte, salt []byte, version uint64) ([]byte, error) { 92 if version == 0 { 93 derivedKey := pbkdf2.Key(key, salt, 8, aesKeyLength, sha256.New) 94 return derivedKey, nil 95 } else { 96 return nil, unknownVersionError(version) 97 } 98 } 99 100 // NewMessage creates and initializes a non-signed, non-encrypted Whisper message. 101 func NewSentMessage(params *MessageParams) *SentMessage { 102 msg := SentMessage{} 103 msg.Raw = make([]byte, 1, len(params.Payload)+len(params.Payload)+signatureLength+padSizeLimitUpper) 104 msg.Raw[0] = 0 // set all the flags to zero 105 msg.appendPadding(params) 106 msg.Raw = append(msg.Raw, params.Payload...) 107 return &msg 108 } 109 110 // appendPadding appends the pseudorandom padding bytes and sets the padding flag. 111 // The last byte contains the size of padding (thus, its size must not exceed 256). 112 func (msg *SentMessage) appendPadding(params *MessageParams) { 113 total := len(params.Payload) + 1 114 if params.Src != nil { 115 total += signatureLength 116 } 117 padChunk := padSizeLimitUpper 118 if total <= padSizeLimitLower { 119 padChunk = padSizeLimitLower 120 } 121 odd := total % padChunk 122 if odd > 0 { 123 padSize := padChunk - odd 124 if padSize > 255 { 125 // this algorithm is only valid if padSizeLimitUpper <= 256. 126 // if padSizeLimitUpper will ever change, please fix the algorithm 127 // (for more information see ReceivedMessage.extractPadding() function). 128 panic("please fix the padding algorithm before releasing new version") 129 } 130 buf := make([]byte, padSize) 131 randomize(buf[1:]) 132 buf[0] = byte(padSize) 133 if params.Padding != nil { 134 copy(buf[1:], params.Padding) 135 } 136 msg.Raw = append(msg.Raw, buf...) 137 msg.Raw[0] |= byte(0x1) // number of bytes indicating the padding size 138 } 139 } 140 141 // sign calculates and sets the cryptographic signature for the message, 142 // also setting the sign flag. 143 func (msg *SentMessage) sign(key *ecdsa.PrivateKey) error { 144 if isMessageSigned(msg.Raw[0]) { 145 // this should not happen, but no reason to panic 146 glog.V(logger.Error).Infof("Trying to sign a message which was already signed") 147 return nil 148 } 149 150 msg.Raw[0] |= signatureFlag 151 hash := crypto.Keccak256(msg.Raw) 152 signature, err := crypto.Sign(hash, key) 153 if err != nil { 154 msg.Raw[0] &= ^signatureFlag // clear the flag 155 return err 156 } 157 msg.Raw = append(msg.Raw, signature...) 158 return nil 159 } 160 161 // encryptAsymmetric encrypts a message with a public key. 162 func (msg *SentMessage) encryptAsymmetric(key *ecdsa.PublicKey) error { 163 if !ValidatePublicKey(key) { 164 return fmt.Errorf("Invalid public key provided for asymmetric encryption") 165 } 166 encrypted, err := crypto.Encrypt(key, msg.Raw) 167 if err == nil { 168 msg.Raw = encrypted 169 } 170 return err 171 } 172 173 // encryptSymmetric encrypts a message with a topic key, using AES-GCM-256. 174 // nonce size should be 12 bytes (see cipher.gcmStandardNonceSize). 175 func (msg *SentMessage) encryptSymmetric(key []byte) (salt []byte, nonce []byte, err error) { 176 if !validateSymmetricKey(key) { 177 return nil, nil, errors.New("invalid key provided for symmetric encryption") 178 } 179 180 salt = make([]byte, saltLength) 181 _, err = crand.Read(salt) 182 if err != nil { 183 return nil, nil, err 184 } else if !validateSymmetricKey(salt) { 185 return nil, nil, errors.New("crypto/rand failed to generate salt") 186 } 187 188 derivedKey, err := DeriveOneTimeKey(key, salt, EnvelopeVersion) 189 if err != nil { 190 return nil, nil, err 191 } 192 if !validateSymmetricKey(derivedKey) { 193 return nil, nil, errors.New("failed to derive one-time key") 194 } 195 block, err := aes.NewCipher(derivedKey) 196 if err != nil { 197 return nil, nil, err 198 } 199 aesgcm, err := cipher.NewGCM(block) 200 if err != nil { 201 return nil, nil, err 202 } 203 204 // never use more than 2^32 random nonces with a given key 205 nonce = make([]byte, aesgcm.NonceSize()) 206 _, err = crand.Read(nonce) 207 if err != nil { 208 return nil, nil, err 209 } else if !validateSymmetricKey(nonce) { 210 return nil, nil, errors.New("crypto/rand failed to generate nonce") 211 } 212 213 msg.Raw = aesgcm.Seal(nil, nonce, msg.Raw, nil) 214 return salt, nonce, nil 215 } 216 217 // Wrap bundles the message into an Envelope to transmit over the network. 218 // 219 // pow (Proof Of Work) controls how much time to spend on hashing the message, 220 // inherently controlling its priority through the network (smaller hash, bigger 221 // priority). 222 // 223 // The user can control the amount of identity, privacy and encryption through 224 // the options parameter as follows: 225 // - options.From == nil && options.To == nil: anonymous broadcast 226 // - options.From != nil && options.To == nil: signed broadcast (known sender) 227 // - options.From == nil && options.To != nil: encrypted anonymous message 228 // - options.From != nil && options.To != nil: encrypted signed message 229 func (msg *SentMessage) Wrap(options *MessageParams) (envelope *Envelope, err error) { 230 if options.TTL == 0 { 231 options.TTL = DefaultTTL 232 } 233 if options.Src != nil { 234 err = msg.sign(options.Src) 235 if err != nil { 236 return nil, err 237 } 238 } 239 if len(msg.Raw) > MaxMessageLength { 240 glog.V(logger.Error).Infof("Message size must not exceed %d bytes", MaxMessageLength) 241 return nil, errors.New("Oversized message") 242 } 243 var salt, nonce []byte 244 if options.Dst != nil { 245 err = msg.encryptAsymmetric(options.Dst) 246 } else if options.KeySym != nil { 247 salt, nonce, err = msg.encryptSymmetric(options.KeySym) 248 } else { 249 err = errors.New("Unable to encrypt the message: neither Dst nor Key") 250 } 251 252 if err != nil { 253 return nil, err 254 } 255 256 envelope = NewEnvelope(options.TTL, options.Topic, salt, nonce, msg) 257 err = envelope.Seal(options) 258 if err != nil { 259 return nil, err 260 } 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, salt []byte, nonce []byte) error { 268 derivedKey, err := DeriveOneTimeKey(key, salt, msg.EnvelopeVersion) 269 if err != nil { 270 return err 271 } 272 273 block, err := aes.NewCipher(derivedKey) 274 if err != nil { 275 return err 276 } 277 aesgcm, err := cipher.NewGCM(block) 278 if err != nil { 279 return err 280 } 281 if len(nonce) != aesgcm.NonceSize() { 282 info := fmt.Sprintf("Wrong AES nonce size - want: %d, got: %d", len(nonce), aesgcm.NonceSize()) 283 glog.V(logger.Error).Infof(info) 284 return errors.New(info) 285 } 286 decrypted, err := aesgcm.Open(nil, nonce, msg.Raw, nil) 287 if err != nil { 288 return err 289 } 290 msg.Raw = decrypted 291 return nil 292 } 293 294 // decryptAsymmetric decrypts an encrypted payload with a private key. 295 func (msg *ReceivedMessage) decryptAsymmetric(key *ecdsa.PrivateKey) error { 296 decrypted, err := crypto.Decrypt(key, msg.Raw) 297 if err == nil { 298 msg.Raw = decrypted 299 } 300 return err 301 } 302 303 // Validate checks the validity and extracts the fields in case of success 304 func (msg *ReceivedMessage) Validate() bool { 305 end := len(msg.Raw) 306 if end < 1 { 307 return false 308 } 309 310 if isMessageSigned(msg.Raw[0]) { 311 end -= signatureLength 312 if end <= 1 { 313 return false 314 } 315 msg.Signature = msg.Raw[end:] 316 msg.Src = msg.SigToPubKey() 317 if msg.Src == nil { 318 return false 319 } 320 } 321 322 padSize, ok := msg.extractPadding(end) 323 if !ok { 324 return false 325 } 326 327 msg.Payload = msg.Raw[1+padSize : end] 328 return true 329 } 330 331 // extractPadding extracts the padding from raw message. 332 // although we don't support sending messages with padding size 333 // exceeding 255 bytes, such messages are perfectly valid, and 334 // can be successfully decrypted. 335 func (msg *ReceivedMessage) extractPadding(end int) (int, bool) { 336 paddingSize := 0 337 sz := int(msg.Raw[0] & paddingMask) // number of bytes containing the entire size of padding, could be zero 338 if sz != 0 { 339 paddingSize = int(bytesToIntLittleEndian(msg.Raw[1 : 1+sz])) 340 if paddingSize < sz || paddingSize+1 > end { 341 return 0, false 342 } 343 msg.Padding = msg.Raw[1+sz : 1+paddingSize] 344 } 345 return paddingSize, true 346 } 347 348 // Recover retrieves the public key of the message signer. 349 func (msg *ReceivedMessage) SigToPubKey() *ecdsa.PublicKey { 350 defer func() { recover() }() // in case of invalid signature 351 352 pub, err := crypto.SigToPub(msg.hash(), msg.Signature) 353 if err != nil { 354 glog.V(logger.Error).Infof("Could not get public key from signature: %v", err) 355 return nil 356 } 357 return pub 358 } 359 360 // hash calculates the SHA3 checksum of the message flags, payload and padding. 361 func (msg *ReceivedMessage) hash() []byte { 362 if isMessageSigned(msg.Raw[0]) { 363 sz := len(msg.Raw) - signatureLength 364 return crypto.Keccak256(msg.Raw[:sz]) 365 } 366 return crypto.Keccak256(msg.Raw) 367 } 368 369 // rand.Rand provides a Read method in Go 1.7 and later, 370 // but we can't use it yet. 371 func randomize(b []byte) { 372 cnt := 0 373 val := mrand.Int63() 374 for n := 0; n < len(b); n++ { 375 b[n] = byte(val) 376 val >>= 8 377 cnt++ 378 if cnt >= 7 { 379 cnt = 0 380 val = mrand.Int63() 381 } 382 } 383 }