github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/whisper/whisperv5/message.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 12:09:51</date> 10 //</624342689046859776> 11 12 // 13 // 14 // 15 // 16 // 17 // 18 // 19 // 20 // 21 // 22 // 23 // 24 // 25 // 26 // 27 28 // 29 30 package whisperv5 31 32 import ( 33 "crypto/aes" 34 "crypto/cipher" 35 "crypto/ecdsa" 36 crand "crypto/rand" 37 "encoding/binary" 38 "errors" 39 "strconv" 40 41 "github.com/ethereum/go-ethereum/common" 42 "github.com/ethereum/go-ethereum/crypto" 43 "github.com/ethereum/go-ethereum/crypto/ecies" 44 "github.com/ethereum/go-ethereum/log" 45 ) 46 47 // 48 type MessageParams struct { 49 TTL uint32 50 Src *ecdsa.PrivateKey 51 Dst *ecdsa.PublicKey 52 KeySym []byte 53 Topic TopicType 54 WorkTime uint32 55 PoW float64 56 Payload []byte 57 Padding []byte 58 } 59 60 // 61 // 62 // 63 type sentMessage struct { 64 Raw []byte 65 } 66 67 // 68 // 69 type ReceivedMessage struct { 70 Raw []byte 71 72 Payload []byte 73 Padding []byte 74 Signature []byte 75 76 PoW float64 // 77 Sent uint32 // 78 TTL uint32 // 79 Src *ecdsa.PublicKey // 80 Dst *ecdsa.PublicKey // 81 Topic TopicType 82 83 SymKeyHash common.Hash // 84 EnvelopeHash common.Hash // 85 EnvelopeVersion uint64 86 } 87 88 func isMessageSigned(flags byte) bool { 89 return (flags & signatureFlag) != 0 90 } 91 92 func (msg *ReceivedMessage) isSymmetricEncryption() bool { 93 return msg.SymKeyHash != common.Hash{} 94 } 95 96 func (msg *ReceivedMessage) isAsymmetricEncryption() bool { 97 return msg.Dst != nil 98 } 99 100 // 101 func NewSentMessage(params *MessageParams) (*sentMessage, error) { 102 msg := sentMessage{} 103 msg.Raw = make([]byte, 1, len(params.Payload)+len(params.Padding)+signatureLength+padSizeLimit) 104 msg.Raw[0] = 0 // 105 err := msg.appendPadding(params) 106 if err != nil { 107 return nil, err 108 } 109 msg.Raw = append(msg.Raw, params.Payload...) 110 return &msg, nil 111 } 112 113 // 114 func getSizeOfLength(b []byte) (sz int, err error) { 115 sz = intSize(len(b)) // 116 sz = intSize(len(b) + sz) // 117 if sz > 3 { 118 err = errors.New("oversized padding parameter") 119 } 120 return sz, err 121 } 122 123 // 124 func intSize(i int) (s int) { 125 for s = 1; i >= 256; s++ { 126 i /= 256 127 } 128 return s 129 } 130 131 // 132 // 133 func (msg *sentMessage) appendPadding(params *MessageParams) error { 134 rawSize := len(params.Payload) + 1 135 if params.Src != nil { 136 rawSize += signatureLength 137 } 138 odd := rawSize % padSizeLimit 139 140 if len(params.Padding) != 0 { 141 padSize := len(params.Padding) 142 padLengthSize, err := getSizeOfLength(params.Padding) 143 if err != nil { 144 return err 145 } 146 totalPadSize := padSize + padLengthSize 147 buf := make([]byte, 8) 148 binary.LittleEndian.PutUint32(buf, uint32(totalPadSize)) 149 buf = buf[:padLengthSize] 150 msg.Raw = append(msg.Raw, buf...) 151 msg.Raw = append(msg.Raw, params.Padding...) 152 msg.Raw[0] |= byte(padLengthSize) // 153 } else if odd != 0 { 154 totalPadSize := padSizeLimit - odd 155 if totalPadSize > 255 { 156 // 157 // 158 // 159 panic("please fix the padding algorithm before releasing new version") 160 } 161 buf := make([]byte, totalPadSize) 162 _, err := crand.Read(buf[1:]) 163 if err != nil { 164 return err 165 } 166 if totalPadSize > 6 && !validateSymmetricKey(buf) { 167 return errors.New("failed to generate random padding of size " + strconv.Itoa(totalPadSize)) 168 } 169 buf[0] = byte(totalPadSize) 170 msg.Raw = append(msg.Raw, buf...) 171 msg.Raw[0] |= byte(0x1) // 172 } 173 return nil 174 } 175 176 // 177 // 178 func (msg *sentMessage) sign(key *ecdsa.PrivateKey) error { 179 if isMessageSigned(msg.Raw[0]) { 180 // 181 log.Error("failed to sign the message: already signed") 182 return nil 183 } 184 185 msg.Raw[0] |= signatureFlag 186 hash := crypto.Keccak256(msg.Raw) 187 signature, err := crypto.Sign(hash, key) 188 if err != nil { 189 msg.Raw[0] &= ^signatureFlag // 190 return err 191 } 192 msg.Raw = append(msg.Raw, signature...) 193 return nil 194 } 195 196 // 197 func (msg *sentMessage) encryptAsymmetric(key *ecdsa.PublicKey) error { 198 if !ValidatePublicKey(key) { 199 return errors.New("invalid public key provided for asymmetric encryption") 200 } 201 encrypted, err := ecies.Encrypt(crand.Reader, ecies.ImportECDSAPublic(key), msg.Raw, nil, nil) 202 if err == nil { 203 msg.Raw = encrypted 204 } 205 return err 206 } 207 208 // 209 // 210 func (msg *sentMessage) encryptSymmetric(key []byte) (nonce []byte, err error) { 211 if !validateSymmetricKey(key) { 212 return nil, errors.New("invalid key provided for symmetric encryption") 213 } 214 215 block, err := aes.NewCipher(key) 216 if err != nil { 217 return nil, err 218 } 219 aesgcm, err := cipher.NewGCM(block) 220 if err != nil { 221 return nil, err 222 } 223 224 // 225 nonce = make([]byte, aesgcm.NonceSize()) 226 _, err = crand.Read(nonce) 227 if err != nil { 228 return nil, err 229 } else if !validateSymmetricKey(nonce) { 230 return nil, errors.New("crypto/rand failed to generate nonce") 231 } 232 233 msg.Raw = aesgcm.Seal(nil, nonce, msg.Raw, nil) 234 return nonce, nil 235 } 236 237 // 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 var nonce []byte 248 if options.Dst != nil { 249 err = msg.encryptAsymmetric(options.Dst) 250 } else if options.KeySym != nil { 251 nonce, err = msg.encryptSymmetric(options.KeySym) 252 } else { 253 err = errors.New("unable to encrypt the message: neither symmetric nor assymmetric key provided") 254 } 255 if err != nil { 256 return nil, err 257 } 258 259 envelope = NewEnvelope(options.TTL, options.Topic, nonce, msg) 260 if err = envelope.Seal(options); err != nil { 261 return nil, err 262 } 263 return envelope, nil 264 } 265 266 // 267 // 268 func (msg *ReceivedMessage) decryptSymmetric(key []byte, nonce []byte) error { 269 block, err := aes.NewCipher(key) 270 if err != nil { 271 return err 272 } 273 aesgcm, err := cipher.NewGCM(block) 274 if err != nil { 275 return err 276 } 277 if len(nonce) != aesgcm.NonceSize() { 278 log.Error("decrypting the message", "AES nonce size", len(nonce)) 279 return errors.New("wrong AES nonce size") 280 } 281 decrypted, err := aesgcm.Open(nil, nonce, msg.Raw, nil) 282 if err != nil { 283 return err 284 } 285 msg.Raw = decrypted 286 return nil 287 } 288 289 // 290 func (msg *ReceivedMessage) decryptAsymmetric(key *ecdsa.PrivateKey) error { 291 decrypted, err := ecies.ImportECDSA(key).Decrypt(msg.Raw, nil, nil) 292 if err == nil { 293 msg.Raw = decrypted 294 } 295 return err 296 } 297 298 // 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 // 327 // 328 // 329 // 330 func (msg *ReceivedMessage) extractPadding(end int) (int, bool) { 331 paddingSize := 0 332 sz := int(msg.Raw[0] & paddingMask) // 333 // 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 // 345 func (msg *ReceivedMessage) SigToPubKey() *ecdsa.PublicKey { 346 defer func() { recover() }() // 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 // 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 } 364