message.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  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. // Contains the Whisper protocol Message element.
  17. package whisperv6
  18. import (
  19. "crypto/aes"
  20. "crypto/cipher"
  21. "crypto/ecdsa"
  22. crand "crypto/rand"
  23. "encoding/binary"
  24. "errors"
  25. mrand "math/rand"
  26. "strconv"
  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. // MessageParams specifies the exact way a message should be wrapped
  33. // into an Envelope.
  34. type MessageParams struct {
  35. TTL uint32
  36. Src *ecdsa.PrivateKey
  37. Dst *ecdsa.PublicKey
  38. KeySym []byte
  39. Topic TopicType
  40. WorkTime uint32
  41. PoW float64
  42. Payload []byte
  43. Padding []byte
  44. }
  45. // SentMessage represents an end-user data packet to transmit through the
  46. // Whisper protocol. These are wrapped into Envelopes that need not be
  47. // understood by intermediate nodes, just forwarded.
  48. type sentMessage struct {
  49. Raw []byte
  50. }
  51. // ReceivedMessage represents a data packet to be received through the
  52. // Whisper protocol and successfully decrypted.
  53. type ReceivedMessage struct {
  54. Raw []byte
  55. Payload []byte
  56. Padding []byte
  57. Signature []byte
  58. Salt []byte
  59. PoW float64 // Proof of work as described in the Whisper spec
  60. Sent uint32 // Time when the message was posted into the network
  61. TTL uint32 // Maximum time to live allowed for the message
  62. Src *ecdsa.PublicKey // Message recipient (identity used to decode the message)
  63. Dst *ecdsa.PublicKey // Message recipient (identity used to decode the message)
  64. Topic TopicType
  65. SymKeyHash common.Hash // The Keccak256Hash of the key
  66. EnvelopeHash common.Hash // Message envelope hash to act as a unique id
  67. }
  68. func isMessageSigned(flags byte) bool {
  69. return (flags & signatureFlag) != 0
  70. }
  71. func (msg *ReceivedMessage) isSymmetricEncryption() bool {
  72. return msg.SymKeyHash != common.Hash{}
  73. }
  74. func (msg *ReceivedMessage) isAsymmetricEncryption() bool {
  75. return msg.Dst != nil
  76. }
  77. // NewSentMessage creates and initializes a non-signed, non-encrypted Whisper message.
  78. func NewSentMessage(params *MessageParams) (*sentMessage, error) {
  79. const payloadSizeFieldMaxSize = 4
  80. msg := sentMessage{}
  81. msg.Raw = make([]byte, 1,
  82. flagsLength+payloadSizeFieldMaxSize+len(params.Payload)+len(params.Padding)+signatureLength+padSizeLimit)
  83. msg.Raw[0] = 0 // set all the flags to zero
  84. msg.addPayloadSizeField(params.Payload)
  85. msg.Raw = append(msg.Raw, params.Payload...)
  86. err := msg.appendPadding(params)
  87. return &msg, err
  88. }
  89. // addPayloadSizeField appends the auxiliary field containing the size of payload
  90. func (msg *sentMessage) addPayloadSizeField(payload []byte) {
  91. fieldSize := getSizeOfPayloadSizeField(payload)
  92. field := make([]byte, 4)
  93. binary.LittleEndian.PutUint32(field, uint32(len(payload)))
  94. field = field[:fieldSize]
  95. msg.Raw = append(msg.Raw, field...)
  96. msg.Raw[0] |= byte(fieldSize)
  97. }
  98. // getSizeOfPayloadSizeField returns the number of bytes necessary to encode the size of payload
  99. func getSizeOfPayloadSizeField(payload []byte) int {
  100. s := 1
  101. for i := len(payload); i >= 256; i /= 256 {
  102. s++
  103. }
  104. return s
  105. }
  106. // appendPadding appends the padding specified in params.
  107. // If no padding is provided in params, then random padding is generated.
  108. func (msg *sentMessage) appendPadding(params *MessageParams) error {
  109. if len(params.Padding) != 0 {
  110. // padding data was provided by the Dapp, just use it as is
  111. msg.Raw = append(msg.Raw, params.Padding...)
  112. return nil
  113. }
  114. rawSize := flagsLength + getSizeOfPayloadSizeField(params.Payload) + len(params.Payload)
  115. if params.Src != nil {
  116. rawSize += signatureLength
  117. }
  118. odd := rawSize % padSizeLimit
  119. paddingSize := padSizeLimit - odd
  120. pad := make([]byte, paddingSize)
  121. _, err := crand.Read(pad)
  122. if err != nil {
  123. return err
  124. }
  125. if !validateDataIntegrity(pad, paddingSize) {
  126. return errors.New("failed to generate random padding of size " + strconv.Itoa(paddingSize))
  127. }
  128. msg.Raw = append(msg.Raw, pad...)
  129. return nil
  130. }
  131. // sign calculates and sets the cryptographic signature for the message,
  132. // also setting the sign flag.
  133. func (msg *sentMessage) sign(key *ecdsa.PrivateKey) error {
  134. if isMessageSigned(msg.Raw[0]) {
  135. // this should not happen, but no reason to panic
  136. log.Error("failed to sign the message: already signed")
  137. return nil
  138. }
  139. msg.Raw[0] |= signatureFlag // it is important to set this flag before signing
  140. hash := crypto.Keccak256(msg.Raw)
  141. signature, err := crypto.Sign(hash, key)
  142. if err != nil {
  143. msg.Raw[0] &= (0xFF ^ signatureFlag) // clear the flag
  144. return err
  145. }
  146. msg.Raw = append(msg.Raw, signature...)
  147. return nil
  148. }
  149. // encryptAsymmetric encrypts a message with a public key.
  150. func (msg *sentMessage) encryptAsymmetric(key *ecdsa.PublicKey) error {
  151. if !ValidatePublicKey(key) {
  152. return errors.New("invalid public key provided for asymmetric encryption")
  153. }
  154. encrypted, err := ecies.Encrypt(crand.Reader, ecies.ImportECDSAPublic(key), msg.Raw, nil, nil)
  155. if err == nil {
  156. msg.Raw = encrypted
  157. }
  158. return err
  159. }
  160. // encryptSymmetric encrypts a message with a topic key, using AES-GCM-256.
  161. // nonce size should be 12 bytes (see cipher.gcmStandardNonceSize).
  162. func (msg *sentMessage) encryptSymmetric(key []byte) (err error) {
  163. if !validateDataIntegrity(key, aesKeyLength) {
  164. return errors.New("invalid key provided for symmetric encryption, size: " + strconv.Itoa(len(key)))
  165. }
  166. block, err := aes.NewCipher(key)
  167. if err != nil {
  168. return err
  169. }
  170. aesgcm, err := cipher.NewGCM(block)
  171. if err != nil {
  172. return err
  173. }
  174. salt, err := generateSecureRandomData(aesNonceLength) // never use more than 2^32 random nonces with a given key
  175. if err != nil {
  176. return err
  177. }
  178. encrypted := aesgcm.Seal(nil, salt, msg.Raw, nil)
  179. msg.Raw = append(encrypted, salt...)
  180. return nil
  181. }
  182. // generateSecureRandomData generates random data where extra security is required.
  183. // The purpose of this function is to prevent some bugs in software or in hardware
  184. // from delivering not-very-random data. This is especially useful for AES nonce,
  185. // where true randomness does not really matter, but it is very important to have
  186. // a unique nonce for every message.
  187. func generateSecureRandomData(length int) ([]byte, error) {
  188. x := make([]byte, length)
  189. y := make([]byte, length)
  190. res := make([]byte, length)
  191. _, err := crand.Read(x)
  192. if err != nil {
  193. return nil, err
  194. } else if !validateDataIntegrity(x, length) {
  195. return nil, errors.New("crypto/rand failed to generate secure random data")
  196. }
  197. _, err = mrand.Read(y)
  198. if err != nil {
  199. return nil, err
  200. } else if !validateDataIntegrity(y, length) {
  201. return nil, errors.New("math/rand failed to generate secure random data")
  202. }
  203. for i := 0; i < length; i++ {
  204. res[i] = x[i] ^ y[i]
  205. }
  206. if !validateDataIntegrity(res, length) {
  207. return nil, errors.New("failed to generate secure random data")
  208. }
  209. return res, nil
  210. }
  211. // Wrap bundles the message into an Envelope to transmit over the network.
  212. func (msg *sentMessage) Wrap(options *MessageParams) (envelope *Envelope, err error) {
  213. if options.TTL == 0 {
  214. options.TTL = DefaultTTL
  215. }
  216. if options.Src != nil {
  217. if err = msg.sign(options.Src); err != nil {
  218. return nil, err
  219. }
  220. }
  221. if options.Dst != nil {
  222. err = msg.encryptAsymmetric(options.Dst)
  223. } else if options.KeySym != nil {
  224. err = msg.encryptSymmetric(options.KeySym)
  225. } else {
  226. err = errors.New("unable to encrypt the message: neither symmetric nor assymmetric key provided")
  227. }
  228. if err != nil {
  229. return nil, err
  230. }
  231. envelope = NewEnvelope(options.TTL, options.Topic, msg)
  232. if err = envelope.Seal(options); err != nil {
  233. return nil, err
  234. }
  235. return envelope, nil
  236. }
  237. // decryptSymmetric decrypts a message with a topic key, using AES-GCM-256.
  238. // nonce size should be 12 bytes (see cipher.gcmStandardNonceSize).
  239. func (msg *ReceivedMessage) decryptSymmetric(key []byte) error {
  240. // symmetric messages are expected to contain the 12-byte nonce at the end of the payload
  241. if len(msg.Raw) < aesNonceLength {
  242. return errors.New("missing salt or invalid payload in symmetric message")
  243. }
  244. salt := msg.Raw[len(msg.Raw)-aesNonceLength:]
  245. block, err := aes.NewCipher(key)
  246. if err != nil {
  247. return err
  248. }
  249. aesgcm, err := cipher.NewGCM(block)
  250. if err != nil {
  251. return err
  252. }
  253. decrypted, err := aesgcm.Open(nil, salt, msg.Raw[:len(msg.Raw)-aesNonceLength], nil)
  254. if err != nil {
  255. return err
  256. }
  257. msg.Raw = decrypted
  258. msg.Salt = salt
  259. return nil
  260. }
  261. // decryptAsymmetric decrypts an encrypted payload with a private key.
  262. func (msg *ReceivedMessage) decryptAsymmetric(key *ecdsa.PrivateKey) error {
  263. decrypted, err := ecies.ImportECDSA(key).Decrypt(msg.Raw, nil, nil)
  264. if err == nil {
  265. msg.Raw = decrypted
  266. }
  267. return err
  268. }
  269. // ValidateAndParse checks the message validity and extracts the fields in case of success.
  270. func (msg *ReceivedMessage) ValidateAndParse() bool {
  271. end := len(msg.Raw)
  272. if end < 1 {
  273. return false
  274. }
  275. if isMessageSigned(msg.Raw[0]) {
  276. end -= signatureLength
  277. if end <= 1 {
  278. return false
  279. }
  280. msg.Signature = msg.Raw[end : end+signatureLength]
  281. msg.Src = msg.SigToPubKey()
  282. if msg.Src == nil {
  283. return false
  284. }
  285. }
  286. beg := 1
  287. payloadSize := 0
  288. sizeOfPayloadSizeField := int(msg.Raw[0] & SizeMask) // number of bytes indicating the size of payload
  289. if sizeOfPayloadSizeField != 0 {
  290. payloadSize = int(bytesToUintLittleEndian(msg.Raw[beg : beg+sizeOfPayloadSizeField]))
  291. if payloadSize+1 > end {
  292. return false
  293. }
  294. beg += sizeOfPayloadSizeField
  295. msg.Payload = msg.Raw[beg : beg+payloadSize]
  296. }
  297. beg += payloadSize
  298. msg.Padding = msg.Raw[beg:end]
  299. return true
  300. }
  301. // SigToPubKey returns the public key associated to the message's
  302. // signature.
  303. func (msg *ReceivedMessage) SigToPubKey() *ecdsa.PublicKey {
  304. defer func() { recover() }() // in case of invalid signature
  305. pub, err := crypto.SigToPub(msg.hash(), msg.Signature)
  306. if err != nil {
  307. log.Error("failed to recover public key from signature", "err", err)
  308. return nil
  309. }
  310. return pub
  311. }
  312. // hash calculates the SHA3 checksum of the message flags, payload size field, payload and padding.
  313. func (msg *ReceivedMessage) hash() []byte {
  314. if isMessageSigned(msg.Raw[0]) {
  315. sz := len(msg.Raw) - signatureLength
  316. return crypto.Keccak256(msg.Raw[:sz])
  317. }
  318. return crypto.Keccak256(msg.Raw)
  319. }