github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/whisper/whisperv6/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 //</624450125548228608> 11 12 13 //包含耳语协议消息元素。 14 15 package whisperv6 16 17 import ( 18 "crypto/aes" 19 "crypto/cipher" 20 "crypto/ecdsa" 21 crand "crypto/rand" 22 "encoding/binary" 23 "errors" 24 mrand "math/rand" 25 "strconv" 26 27 "github.com/ethereum/go-ethereum/common" 28 "github.com/ethereum/go-ethereum/crypto" 29 "github.com/ethereum/go-ethereum/crypto/ecies" 30 "github.com/ethereum/go-ethereum/log" 31 ) 32 33 //messageparams指定邮件的包装方式 34 //装进信封里。 35 type MessageParams struct { 36 TTL uint32 37 Src *ecdsa.PrivateKey 38 Dst *ecdsa.PublicKey 39 KeySym []byte 40 Topic TopicType 41 WorkTime uint32 42 PoW float64 43 Payload []byte 44 Padding []byte 45 } 46 47 //sentmessage表示要通过 48 //耳语协议。它们被包装成信封,不需要 49 //中间节点理解,刚刚转发。 50 type sentMessage struct { 51 Raw []byte 52 } 53 54 //ReceivedMessage表示要通过 55 //并成功解密。 56 type ReceivedMessage struct { 57 Raw []byte 58 59 Payload []byte 60 Padding []byte 61 Signature []byte 62 Salt []byte 63 64 PoW float64 //耳语规范中所述的工作证明 65 Sent uint32 //消息发布到网络的时间 66 TTL uint32 //消息允许的最长生存时间 67 Src *ecdsa.PublicKey //邮件收件人(用于解码邮件的标识) 68 Dst *ecdsa.PublicKey //邮件收件人(用于解码邮件的标识) 69 Topic TopicType 70 71 SymKeyHash common.Hash //密钥的keccak256哈希 72 EnvelopeHash common.Hash //作为唯一ID的消息信封哈希 73 } 74 75 func isMessageSigned(flags byte) bool { 76 return (flags & signatureFlag) != 0 77 } 78 79 func (msg *ReceivedMessage) isSymmetricEncryption() bool { 80 return msg.SymKeyHash != common.Hash{} 81 } 82 83 func (msg *ReceivedMessage) isAsymmetricEncryption() bool { 84 return msg.Dst != nil 85 } 86 87 //newsentmessage创建并初始化一个未签名、未加密的悄悄消息。 88 func NewSentMessage(params *MessageParams) (*sentMessage, error) { 89 const payloadSizeFieldMaxSize = 4 90 msg := sentMessage{} 91 msg.Raw = make([]byte, 1, 92 flagsLength+payloadSizeFieldMaxSize+len(params.Payload)+len(params.Padding)+signatureLength+padSizeLimit) 93 msg.Raw[0] = 0 //将所有标志设置为零 94 msg.addPayloadSizeField(params.Payload) 95 msg.Raw = append(msg.Raw, params.Payload...) 96 err := msg.appendPadding(params) 97 return &msg, err 98 } 99 100 //AddPayLoadSizeField附加包含有效负载大小的辅助字段 101 func (msg *sentMessage) addPayloadSizeField(payload []byte) { 102 fieldSize := getSizeOfPayloadSizeField(payload) 103 field := make([]byte, 4) 104 binary.LittleEndian.PutUint32(field, uint32(len(payload))) 105 field = field[:fieldSize] 106 msg.Raw = append(msg.Raw, field...) 107 msg.Raw[0] |= byte(fieldSize) 108 } 109 110 //GetSizeOfPayLoadSizeField返回对有效负载大小进行编码所需的字节数。 111 func getSizeOfPayloadSizeField(payload []byte) int { 112 s := 1 113 for i := len(payload); i >= 256; i /= 256 { 114 s++ 115 } 116 return s 117 } 118 119 //AppendPadding追加参数中指定的填充。 120 //如果参数中没有提供填充,则生成随机填充。 121 func (msg *sentMessage) appendPadding(params *MessageParams) error { 122 if len(params.Padding) != 0 { 123 //填充数据由DAPP提供,按原样使用 124 msg.Raw = append(msg.Raw, params.Padding...) 125 return nil 126 } 127 128 rawSize := flagsLength + getSizeOfPayloadSizeField(params.Payload) + len(params.Payload) 129 if params.Src != nil { 130 rawSize += signatureLength 131 } 132 odd := rawSize % padSizeLimit 133 paddingSize := padSizeLimit - odd 134 pad := make([]byte, paddingSize) 135 _, err := crand.Read(pad) 136 if err != nil { 137 return err 138 } 139 if !validateDataIntegrity(pad, paddingSize) { 140 return errors.New("failed to generate random padding of size " + strconv.Itoa(paddingSize)) 141 } 142 msg.Raw = append(msg.Raw, pad...) 143 return nil 144 } 145 146 //sign计算并设置消息的加密签名, 147 //同时设置标志标志。 148 func (msg *sentMessage) sign(key *ecdsa.PrivateKey) error { 149 if isMessageSigned(msg.Raw[0]) { 150 //这不应该发生,但没有理由惊慌 151 log.Error("failed to sign the message: already signed") 152 return nil 153 } 154 155 msg.Raw[0] |= signatureFlag //在签名前设置此标志很重要 156 hash := crypto.Keccak256(msg.Raw) 157 signature, err := crypto.Sign(hash, key) 158 if err != nil { 159 msg.Raw[0] &= (0xFF ^ signatureFlag) //清旗 160 return err 161 } 162 msg.Raw = append(msg.Raw, signature...) 163 return nil 164 } 165 166 //加密非对称使用公钥加密消息。 167 func (msg *sentMessage) encryptAsymmetric(key *ecdsa.PublicKey) error { 168 if !ValidatePublicKey(key) { 169 return errors.New("invalid public key provided for asymmetric encryption") 170 } 171 encrypted, err := ecies.Encrypt(crand.Reader, ecies.ImportECDSAPublic(key), msg.Raw, nil, nil) 172 if err == nil { 173 msg.Raw = encrypted 174 } 175 return err 176 } 177 178 //encryptsymmetric使用aes-gcm-256使用主题密钥对消息进行加密。 179 //nonce大小应为12个字节(请参阅cipher.gcmstandardnoncosize)。 180 func (msg *sentMessage) encryptSymmetric(key []byte) (err error) { 181 if !validateDataIntegrity(key, aesKeyLength) { 182 return errors.New("invalid key provided for symmetric encryption, size: " + strconv.Itoa(len(key))) 183 } 184 block, err := aes.NewCipher(key) 185 if err != nil { 186 return err 187 } 188 aesgcm, err := cipher.NewGCM(block) 189 if err != nil { 190 return err 191 } 192 salt, err := generateSecureRandomData(aesNonceLength) //对于给定的键,不要使用超过2^32个随机nonce 193 if err != nil { 194 return err 195 } 196 encrypted := aesgcm.Seal(nil, salt, msg.Raw, nil) 197 msg.Raw = append(encrypted, salt...) 198 return nil 199 } 200 201 //generatesecurerandomdata在需要额外安全性的地方生成随机数据。 202 //此功能的目的是防止软件或硬件中的某些错误 203 //提供不太随机的数据。这对aes nonce特别有用, 204 //真正的随机性并不重要,但是 205 //每封邮件都是独一无二的。 206 func generateSecureRandomData(length int) ([]byte, error) { 207 x := make([]byte, length) 208 y := make([]byte, length) 209 res := make([]byte, length) 210 211 _, err := crand.Read(x) 212 if err != nil { 213 return nil, err 214 } else if !validateDataIntegrity(x, length) { 215 return nil, errors.New("crypto/rand failed to generate secure random data") 216 } 217 _, err = mrand.Read(y) 218 if err != nil { 219 return nil, err 220 } else if !validateDataIntegrity(y, length) { 221 return nil, errors.New("math/rand failed to generate secure random data") 222 } 223 for i := 0; i < length; i++ { 224 res[i] = x[i] ^ y[i] 225 } 226 if !validateDataIntegrity(res, length) { 227 return nil, errors.New("failed to generate secure random data") 228 } 229 return res, nil 230 } 231 232 //将消息打包成一个信封,通过网络传输。 233 func (msg *sentMessage) Wrap(options *MessageParams) (envelope *Envelope, err error) { 234 if options.TTL == 0 { 235 options.TTL = DefaultTTL 236 } 237 if options.Src != nil { 238 if err = msg.sign(options.Src); err != nil { 239 return nil, err 240 } 241 } 242 if options.Dst != nil { 243 err = msg.encryptAsymmetric(options.Dst) 244 } else if options.KeySym != nil { 245 err = msg.encryptSymmetric(options.KeySym) 246 } else { 247 err = errors.New("unable to encrypt the message: neither symmetric nor assymmetric key provided") 248 } 249 if err != nil { 250 return nil, err 251 } 252 253 envelope = NewEnvelope(options.TTL, options.Topic, msg) 254 if err = envelope.Seal(options); err != nil { 255 return nil, err 256 } 257 return envelope, nil 258 } 259 260 //decryptsymmetric使用aes-gcm-256使用主题密钥解密消息。 261 //nonce大小应为12个字节(请参阅cipher.gcmstandardnoncosize)。 262 func (msg *ReceivedMessage) decryptSymmetric(key []byte) error { 263 //对称消息应在有效负载末尾包含12字节的nonce 264 if len(msg.Raw) < aesNonceLength { 265 return errors.New("missing salt or invalid payload in symmetric message") 266 } 267 salt := msg.Raw[len(msg.Raw)-aesNonceLength:] 268 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 decrypted, err := aesgcm.Open(nil, salt, msg.Raw[:len(msg.Raw)-aesNonceLength], nil) 278 if err != nil { 279 return err 280 } 281 msg.Raw = decrypted 282 msg.Salt = salt 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 //validateAndParse检查消息的有效性,并在成功时提取字段。 296 func (msg *ReceivedMessage) ValidateAndParse() 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 : end+signatureLength] 308 msg.Src = msg.SigToPubKey() 309 if msg.Src == nil { 310 return false 311 } 312 } 313 314 beg := 1 315 payloadSize := 0 316 sizeOfPayloadSizeField := int(msg.Raw[0] & SizeMask) //指示有效负载大小的字节数 317 if sizeOfPayloadSizeField != 0 { 318 payloadSize = int(bytesToUintLittleEndian(msg.Raw[beg : beg+sizeOfPayloadSizeField])) 319 if payloadSize+1 > end { 320 return false 321 } 322 beg += sizeOfPayloadSizeField 323 msg.Payload = msg.Raw[beg : beg+payloadSize] 324 } 325 326 beg += payloadSize 327 msg.Padding = msg.Raw[beg:end] 328 return true 329 } 330 331 //sigtopubkey返回与消息的 332 //签名。 333 func (msg *ReceivedMessage) SigToPubKey() *ecdsa.PublicKey { 334 defer func() { recover() }() //如果签名无效 335 336 pub, err := crypto.SigToPub(msg.hash(), msg.Signature) 337 if err != nil { 338 log.Error("failed to recover public key from signature", "err", err) 339 return nil 340 } 341 return pub 342 } 343 344 //hash计算消息标志、有效负载大小字段、有效负载和填充的sha3校验和。 345 func (msg *ReceivedMessage) hash() []byte { 346 if isMessageSigned(msg.Raw[0]) { 347 sz := len(msg.Raw) - signatureLength 348 return crypto.Keccak256(msg.Raw[:sz]) 349 } 350 return crypto.Keccak256(msg.Raw) 351 } 352