github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/whisper/whisperv5/message.go (about) 1 2 //此源码被清华学神尹成大魔王专业翻译分析并修改 3 //尹成QQ77025077 4 //尹成微信18510341407 5 //尹成所在QQ群721929980 6 //尹成邮箱 yinc13@mails.tsinghua.edu.cn 7 //尹成毕业于清华大学,微软区块链领域全球最有价值专家 8 //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620 9 // 10 // 11 // 12 // 13 // 14 // 15 // 16 // 17 // 18 // 19 // 20 // 21 // 22 // 23 // 24 25 // 26 27 package whisperv5 28 29 import ( 30 "crypto/aes" 31 "crypto/cipher" 32 "crypto/ecdsa" 33 crand "crypto/rand" 34 "encoding/binary" 35 "errors" 36 "strconv" 37 38 "github.com/ethereum/go-ethereum/common" 39 "github.com/ethereum/go-ethereum/crypto" 40 "github.com/ethereum/go-ethereum/crypto/ecies" 41 "github.com/ethereum/go-ethereum/log" 42 ) 43 44 // 45 type MessageParams struct { 46 TTL uint32 47 Src *ecdsa.PrivateKey 48 Dst *ecdsa.PublicKey 49 KeySym []byte 50 Topic TopicType 51 WorkTime uint32 52 PoW float64 53 Payload []byte 54 Padding []byte 55 } 56 57 // 58 // 59 // 60 type sentMessage struct { 61 Raw []byte 62 } 63 64 // 65 // 66 type ReceivedMessage struct { 67 Raw []byte 68 69 Payload []byte 70 Padding []byte 71 Signature []byte 72 73 PoW float64 // 74 Sent uint32 // 75 TTL uint32 // 76 Src *ecdsa.PublicKey // 77 Dst *ecdsa.PublicKey // 78 Topic TopicType 79 80 SymKeyHash common.Hash // 81 EnvelopeHash common.Hash // 82 EnvelopeVersion uint64 83 } 84 85 func isMessageSigned(flags byte) bool { 86 return (flags & signatureFlag) != 0 87 } 88 89 func (msg *ReceivedMessage) isSymmetricEncryption() bool { 90 return msg.SymKeyHash != common.Hash{} 91 } 92 93 func (msg *ReceivedMessage) isAsymmetricEncryption() bool { 94 return msg.Dst != nil 95 } 96 97 // 98 func NewSentMessage(params *MessageParams) (*sentMessage, error) { 99 msg := sentMessage{} 100 msg.Raw = make([]byte, 1, len(params.Payload)+len(params.Padding)+signatureLength+padSizeLimit) 101 msg.Raw[0] = 0 // 102 err := msg.appendPadding(params) 103 if err != nil { 104 return nil, err 105 } 106 msg.Raw = append(msg.Raw, params.Payload...) 107 return &msg, nil 108 } 109 110 // 111 func getSizeOfLength(b []byte) (sz int, err error) { 112 sz = intSize(len(b)) // 113 sz = intSize(len(b) + sz) // 114 if sz > 3 { 115 err = errors.New("oversized padding parameter") 116 } 117 return sz, err 118 } 119 120 // 121 func intSize(i int) (s int) { 122 for s = 1; i >= 256; s++ { 123 i /= 256 124 } 125 return s 126 } 127 128 // 129 // 130 func (msg *sentMessage) appendPadding(params *MessageParams) error { 131 rawSize := len(params.Payload) + 1 132 if params.Src != nil { 133 rawSize += signatureLength 134 } 135 odd := rawSize % padSizeLimit 136 137 if len(params.Padding) != 0 { 138 padSize := len(params.Padding) 139 padLengthSize, err := getSizeOfLength(params.Padding) 140 if err != nil { 141 return err 142 } 143 totalPadSize := padSize + padLengthSize 144 buf := make([]byte, 8) 145 binary.LittleEndian.PutUint32(buf, uint32(totalPadSize)) 146 buf = buf[:padLengthSize] 147 msg.Raw = append(msg.Raw, buf...) 148 msg.Raw = append(msg.Raw, params.Padding...) 149 msg.Raw[0] |= byte(padLengthSize) // 150 } else if odd != 0 { 151 totalPadSize := padSizeLimit - odd 152 if totalPadSize > 255 { 153 // 154 // 155 // 156 panic("please fix the padding algorithm before releasing new version") 157 } 158 buf := make([]byte, totalPadSize) 159 _, err := crand.Read(buf[1:]) 160 if err != nil { 161 return err 162 } 163 if totalPadSize > 6 && !validateSymmetricKey(buf) { 164 return errors.New("failed to generate random padding of size " + strconv.Itoa(totalPadSize)) 165 } 166 buf[0] = byte(totalPadSize) 167 msg.Raw = append(msg.Raw, buf...) 168 msg.Raw[0] |= byte(0x1) // 169 } 170 return nil 171 } 172 173 // 174 // 175 func (msg *sentMessage) sign(key *ecdsa.PrivateKey) error { 176 if isMessageSigned(msg.Raw[0]) { 177 // 178 log.Error("failed to sign the message: already signed") 179 return nil 180 } 181 182 msg.Raw[0] |= signatureFlag 183 hash := crypto.Keccak256(msg.Raw) 184 signature, err := crypto.Sign(hash, key) 185 if err != nil { 186 msg.Raw[0] &= ^signatureFlag // 187 return err 188 } 189 msg.Raw = append(msg.Raw, signature...) 190 return nil 191 } 192 193 // 194 func (msg *sentMessage) encryptAsymmetric(key *ecdsa.PublicKey) error { 195 if !ValidatePublicKey(key) { 196 return errors.New("invalid public key provided for asymmetric encryption") 197 } 198 encrypted, err := ecies.Encrypt(crand.Reader, ecies.ImportECDSAPublic(key), msg.Raw, nil, nil) 199 if err == nil { 200 msg.Raw = encrypted 201 } 202 return err 203 } 204 205 // 206 // 207 func (msg *sentMessage) encryptSymmetric(key []byte) (nonce []byte, err error) { 208 if !validateSymmetricKey(key) { 209 return nil, errors.New("invalid key provided for symmetric encryption") 210 } 211 212 block, err := aes.NewCipher(key) 213 if err != nil { 214 return nil, err 215 } 216 aesgcm, err := cipher.NewGCM(block) 217 if err != nil { 218 return nil, err 219 } 220 221 // 222 nonce = make([]byte, aesgcm.NonceSize()) 223 _, err = crand.Read(nonce) 224 if err != nil { 225 return nil, err 226 } else if !validateSymmetricKey(nonce) { 227 return nil, errors.New("crypto/rand failed to generate nonce") 228 } 229 230 msg.Raw = aesgcm.Seal(nil, nonce, msg.Raw, nil) 231 return nonce, nil 232 } 233 234 // 235 func (msg *sentMessage) Wrap(options *MessageParams) (envelope *Envelope, err error) { 236 if options.TTL == 0 { 237 options.TTL = DefaultTTL 238 } 239 if options.Src != nil { 240 if err = msg.sign(options.Src); err != nil { 241 return nil, err 242 } 243 } 244 var nonce []byte 245 if options.Dst != nil { 246 err = msg.encryptAsymmetric(options.Dst) 247 } else if options.KeySym != nil { 248 nonce, err = msg.encryptSymmetric(options.KeySym) 249 } else { 250 err = errors.New("unable to encrypt the message: neither symmetric nor assymmetric key provided") 251 } 252 if err != nil { 253 return nil, err 254 } 255 256 envelope = NewEnvelope(options.TTL, options.Topic, nonce, msg) 257 if err = envelope.Seal(options); err != nil { 258 return nil, err 259 } 260 return envelope, nil 261 } 262 263 // 264 // 265 func (msg *ReceivedMessage) decryptSymmetric(key []byte, nonce []byte) error { 266 block, err := aes.NewCipher(key) 267 if err != nil { 268 return err 269 } 270 aesgcm, err := cipher.NewGCM(block) 271 if err != nil { 272 return err 273 } 274 if len(nonce) != aesgcm.NonceSize() { 275 log.Error("decrypting the message", "AES nonce size", len(nonce)) 276 return errors.New("wrong AES nonce size") 277 } 278 decrypted, err := aesgcm.Open(nil, nonce, msg.Raw, nil) 279 if err != nil { 280 return err 281 } 282 msg.Raw = decrypted 283 return nil 284 } 285 286 // 287 func (msg *ReceivedMessage) decryptAsymmetric(key *ecdsa.PrivateKey) error { 288 decrypted, err := ecies.ImportECDSA(key).Decrypt(msg.Raw, nil, nil) 289 if err == nil { 290 msg.Raw = decrypted 291 } 292 return err 293 } 294 295 // 296 func (msg *ReceivedMessage) Validate() bool { 297 end := len(msg.Raw) 298 if end < 1 { 299 return false 300 } 301 302 if isMessageSigned(msg.Raw[0]) { 303 end -= signatureLength 304 if end <= 1 { 305 return false 306 } 307 msg.Signature = msg.Raw[end:] 308 msg.Src = msg.SigToPubKey() 309 if msg.Src == nil { 310 return false 311 } 312 } 313 314 padSize, ok := msg.extractPadding(end) 315 if !ok { 316 return false 317 } 318 319 msg.Payload = msg.Raw[1+padSize : end] 320 return true 321 } 322 323 // 324 // 325 // 326 // 327 func (msg *ReceivedMessage) extractPadding(end int) (int, bool) { 328 paddingSize := 0 329 sz := int(msg.Raw[0] & paddingMask) // 330 // 331 if sz != 0 { 332 paddingSize = int(bytesToUintLittleEndian(msg.Raw[1 : 1+sz])) 333 if paddingSize < sz || paddingSize+1 > end { 334 return 0, false 335 } 336 msg.Padding = msg.Raw[1+sz : 1+paddingSize] 337 } 338 return paddingSize, true 339 } 340 341 // 342 func (msg *ReceivedMessage) SigToPubKey() *ecdsa.PublicKey { 343 defer func() { recover() }() // 344 345 pub, err := crypto.SigToPub(msg.hash(), msg.Signature) 346 if err != nil { 347 log.Error("failed to recover public key from signature", "err", err) 348 return nil 349 } 350 return pub 351 } 352 353 // 354 func (msg *ReceivedMessage) hash() []byte { 355 if isMessageSigned(msg.Raw[0]) { 356 sz := len(msg.Raw) - signatureLength 357 return crypto.Keccak256(msg.Raw[:sz]) 358 } 359 return crypto.Keccak256(msg.Raw) 360 }