github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/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 19:16:46</date> 10 //</624450124650647552> 11 12 13 //包含耳语协议消息元素。 14 15 package whisperv5 16 17 import ( 18 "crypto/aes" 19 "crypto/cipher" 20 "crypto/ecdsa" 21 crand "crypto/rand" 22 "encoding/binary" 23 "errors" 24 "strconv" 25 26 "github.com/ethereum/go-ethereum/common" 27 "github.com/ethereum/go-ethereum/crypto" 28 "github.com/ethereum/go-ethereum/crypto/ecies" 29 "github.com/ethereum/go-ethereum/log" 30 ) 31 32 //messageparams指定将消息包装到信封中的确切方式。 33 type MessageParams struct { 34 TTL uint32 35 Src *ecdsa.PrivateKey 36 Dst *ecdsa.PublicKey 37 KeySym []byte 38 Topic TopicType 39 WorkTime uint32 40 PoW float64 41 Payload []byte 42 Padding []byte 43 } 44 45 //sentmessage表示要通过 46 //耳语协议。它们被包装成信封,不需要 47 //中间节点理解,刚刚转发。 48 type sentMessage struct { 49 Raw []byte 50 } 51 52 //ReceivedMessage表示要通过 53 //耳语协议。 54 type ReceivedMessage struct { 55 Raw []byte 56 57 Payload []byte 58 Padding []byte 59 Signature []byte 60 61 PoW float64 //耳语规范中所述的工作证明 62 Sent uint32 //消息发布到网络的时间 63 TTL uint32 //消息允许的最长生存时间 64 Src *ecdsa.PublicKey //邮件收件人(用于解码邮件的标识) 65 Dst *ecdsa.PublicKey //邮件收件人(用于解码邮件的标识) 66 Topic TopicType 67 68 SymKeyHash common.Hash //与主题关联的密钥的keccak256hash 69 EnvelopeHash common.Hash //作为唯一ID的消息信封哈希 70 EnvelopeVersion uint64 71 } 72 73 func isMessageSigned(flags byte) bool { 74 return (flags & signatureFlag) != 0 75 } 76 77 func (msg *ReceivedMessage) isSymmetricEncryption() bool { 78 return msg.SymKeyHash != common.Hash{} 79 } 80 81 func (msg *ReceivedMessage) isAsymmetricEncryption() bool { 82 return msg.Dst != nil 83 } 84 85 //newsentmessage创建并初始化一个未签名、未加密的悄悄消息。 86 func NewSentMessage(params *MessageParams) (*sentMessage, error) { 87 msg := sentMessage{} 88 msg.Raw = make([]byte, 1, len(params.Payload)+len(params.Padding)+signatureLength+padSizeLimit) 89 msg.Raw[0] = 0 //将所有标志设置为零 90 err := msg.appendPadding(params) 91 if err != nil { 92 return nil, err 93 } 94 msg.Raw = append(msg.Raw, params.Payload...) 95 return &msg, nil 96 } 97 98 //getsizeoflength返回对整个大小填充进行编码所需的字节数(包括这些字节) 99 func getSizeOfLength(b []byte) (sz int, err error) { 100 sz = intSize(len(b)) //第一次迭代 101 sz = intSize(len(b) + sz) //第二次迭代 102 if sz > 3 { 103 err = errors.New("oversized padding parameter") 104 } 105 return sz, err 106 } 107 108 //sizeofinsize返回对整数值进行编码所需的最小字节数 109 func intSize(i int) (s int) { 110 for s = 1; i >= 256; s++ { 111 i /= 256 112 } 113 return s 114 } 115 116 //AppendPadding附加伪随机填充字节并设置填充标志。 117 //最后一个字节包含填充大小(因此,其大小不能超过256)。 118 func (msg *sentMessage) appendPadding(params *MessageParams) error { 119 rawSize := len(params.Payload) + 1 120 if params.Src != nil { 121 rawSize += signatureLength 122 } 123 odd := rawSize % padSizeLimit 124 125 if len(params.Padding) != 0 { 126 padSize := len(params.Padding) 127 padLengthSize, err := getSizeOfLength(params.Padding) 128 if err != nil { 129 return err 130 } 131 totalPadSize := padSize + padLengthSize 132 buf := make([]byte, 8) 133 binary.LittleEndian.PutUint32(buf, uint32(totalPadSize)) 134 buf = buf[:padLengthSize] 135 msg.Raw = append(msg.Raw, buf...) 136 msg.Raw = append(msg.Raw, params.Padding...) 137 msg.Raw[0] |= byte(padLengthSize) //指示填充大小的字节数 138 } else if odd != 0 { 139 totalPadSize := padSizeLimit - odd 140 if totalPadSize > 255 { 141 //此算法仅在padsizelimit<256时有效。 142 //如果padsizelimit将更改,请修复算法 143 //(另请参见receivedmessage.extractpadding()函数)。 144 panic("please fix the padding algorithm before releasing new version") 145 } 146 buf := make([]byte, totalPadSize) 147 _, err := crand.Read(buf[1:]) 148 if err != nil { 149 return err 150 } 151 if totalPadSize > 6 && !validateSymmetricKey(buf) { 152 return errors.New("failed to generate random padding of size " + strconv.Itoa(totalPadSize)) 153 } 154 buf[0] = byte(totalPadSize) 155 msg.Raw = append(msg.Raw, buf...) 156 msg.Raw[0] |= byte(0x1) //指示填充大小的字节数 157 } 158 return nil 159 } 160 161 //sign计算并设置消息的加密签名, 162 //同时设置标志标志。 163 func (msg *sentMessage) sign(key *ecdsa.PrivateKey) error { 164 if isMessageSigned(msg.Raw[0]) { 165 //这不应该发生,但没有理由惊慌 166 log.Error("failed to sign the message: already signed") 167 return nil 168 } 169 170 msg.Raw[0] |= signatureFlag 171 hash := crypto.Keccak256(msg.Raw) 172 signature, err := crypto.Sign(hash, key) 173 if err != nil { 174 msg.Raw[0] &= ^signatureFlag //清旗 175 return err 176 } 177 msg.Raw = append(msg.Raw, signature...) 178 return nil 179 } 180 181 //加密非对称使用公钥加密消息。 182 func (msg *sentMessage) encryptAsymmetric(key *ecdsa.PublicKey) error { 183 if !ValidatePublicKey(key) { 184 return errors.New("invalid public key provided for asymmetric encryption") 185 } 186 encrypted, err := ecies.Encrypt(crand.Reader, ecies.ImportECDSAPublic(key), msg.Raw, nil, nil) 187 if err == nil { 188 msg.Raw = encrypted 189 } 190 return err 191 } 192 193 //encryptsymmetric使用aes-gcm-256使用主题密钥对消息进行加密。 194 //nonce大小应为12个字节(请参阅cipher.gcmstandardnoncosize)。 195 func (msg *sentMessage) encryptSymmetric(key []byte) (nonce []byte, err error) { 196 if !validateSymmetricKey(key) { 197 return nil, errors.New("invalid key provided for symmetric encryption") 198 } 199 200 block, err := aes.NewCipher(key) 201 if err != nil { 202 return nil, err 203 } 204 aesgcm, err := cipher.NewGCM(block) 205 if err != nil { 206 return nil, err 207 } 208 209 //对于给定的键,不要使用超过2^32个随机nonce 210 nonce = make([]byte, aesgcm.NonceSize()) 211 _, err = crand.Read(nonce) 212 if err != nil { 213 return nil, err 214 } else if !validateSymmetricKey(nonce) { 215 return nil, errors.New("crypto/rand failed to generate nonce") 216 } 217 218 msg.Raw = aesgcm.Seal(nil, nonce, msg.Raw, nil) 219 return nonce, nil 220 } 221 222 //将消息打包成一个信封,通过网络传输。 223 func (msg *sentMessage) Wrap(options *MessageParams) (envelope *Envelope, err error) { 224 if options.TTL == 0 { 225 options.TTL = DefaultTTL 226 } 227 if options.Src != nil { 228 if err = msg.sign(options.Src); err != nil { 229 return nil, err 230 } 231 } 232 var nonce []byte 233 if options.Dst != nil { 234 err = msg.encryptAsymmetric(options.Dst) 235 } else if options.KeySym != nil { 236 nonce, err = msg.encryptSymmetric(options.KeySym) 237 } else { 238 err = errors.New("unable to encrypt the message: neither symmetric nor assymmetric key provided") 239 } 240 if err != nil { 241 return nil, err 242 } 243 244 envelope = NewEnvelope(options.TTL, options.Topic, nonce, msg) 245 if err = envelope.Seal(options); err != nil { 246 return nil, err 247 } 248 return envelope, nil 249 } 250 251 //decryptsymmetric使用aes-gcm-256使用主题密钥解密消息。 252 //nonce大小应为12个字节(请参阅cipher.gcmstandardnoncosize)。 253 func (msg *ReceivedMessage) decryptSymmetric(key []byte, nonce []byte) error { 254 block, err := aes.NewCipher(key) 255 if err != nil { 256 return err 257 } 258 aesgcm, err := cipher.NewGCM(block) 259 if err != nil { 260 return err 261 } 262 if len(nonce) != aesgcm.NonceSize() { 263 log.Error("decrypting the message", "AES nonce size", len(nonce)) 264 return errors.New("wrong AES nonce size") 265 } 266 decrypted, err := aesgcm.Open(nil, nonce, msg.Raw, nil) 267 if err != nil { 268 return err 269 } 270 msg.Raw = decrypted 271 return nil 272 } 273 274 //解密非对称使用私钥解密加密的负载。 275 func (msg *ReceivedMessage) decryptAsymmetric(key *ecdsa.PrivateKey) error { 276 decrypted, err := ecies.ImportECDSA(key).Decrypt(msg.Raw, nil, nil) 277 if err == nil { 278 msg.Raw = decrypted 279 } 280 return err 281 } 282 283 //验证检查有效性并在成功时提取字段 284 func (msg *ReceivedMessage) Validate() bool { 285 end := len(msg.Raw) 286 if end < 1 { 287 return false 288 } 289 290 if isMessageSigned(msg.Raw[0]) { 291 end -= signatureLength 292 if end <= 1 { 293 return false 294 } 295 msg.Signature = msg.Raw[end:] 296 msg.Src = msg.SigToPubKey() 297 if msg.Src == nil { 298 return false 299 } 300 } 301 302 padSize, ok := msg.extractPadding(end) 303 if !ok { 304 return false 305 } 306 307 msg.Payload = msg.Raw[1+padSize : end] 308 return true 309 } 310 311 //提取填充从原始消息中提取填充。 312 //尽管我们不支持发送填充大小的邮件 313 //超过255字节,此类消息完全有效,并且 314 //可以成功解密。 315 func (msg *ReceivedMessage) extractPadding(end int) (int, bool) { 316 paddingSize := 0 317 sz := int(msg.Raw[0] & paddingMask) //指示填充整个大小的字节数(包括这些字节) 318 //可能是零——意味着没有填充 319 if sz != 0 { 320 paddingSize = int(bytesToUintLittleEndian(msg.Raw[1 : 1+sz])) 321 if paddingSize < sz || paddingSize+1 > end { 322 return 0, false 323 } 324 msg.Padding = msg.Raw[1+sz : 1+paddingSize] 325 } 326 return paddingSize, true 327 } 328 329 //sigtopubkey检索消息签名者的公钥。 330 func (msg *ReceivedMessage) SigToPubKey() *ecdsa.PublicKey { 331 defer func() { recover() }() //如果签名无效 332 333 pub, err := crypto.SigToPub(msg.hash(), msg.Signature) 334 if err != nil { 335 log.Error("failed to recover public key from signature", "err", err) 336 return nil 337 } 338 return pub 339 } 340 341 //hash计算消息标志、有效负载和填充的sha3校验和。 342 func (msg *ReceivedMessage) hash() []byte { 343 if isMessageSigned(msg.Raw[0]) { 344 sz := len(msg.Raw) - signatureLength 345 return crypto.Keccak256(msg.Raw[:sz]) 346 } 347 return crypto.Keccak256(msg.Raw) 348 } 349