message.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  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 whisperv5
  18. import (
  19. "crypto/aes"
  20. "crypto/cipher"
  21. "crypto/ecdsa"
  22. crand "crypto/rand"
  23. "crypto/sha256"
  24. "errors"
  25. "fmt"
  26. mrand "math/rand"
  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/logger"
  31. "github.com/ethereum/go-ethereum/logger/glog"
  32. "golang.org/x/crypto/pbkdf2"
  33. )
  34. // Options specifies the exact way a message should be wrapped into an Envelope.
  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. // SentMessage represents an end-user data packet to transmit through the
  47. // Whisper protocol. These are wrapped into Envelopes that need not be
  48. // understood by intermediate nodes, just forwarded.
  49. type SentMessage struct {
  50. Raw []byte
  51. }
  52. // ReceivedMessage represents a data packet to be received through the
  53. // Whisper protocol.
  54. type ReceivedMessage struct {
  55. Raw []byte
  56. Payload []byte
  57. Padding []byte
  58. Signature []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, associated with the Topic
  66. EnvelopeHash common.Hash // Message envelope hash to act as a unique id
  67. EnvelopeVersion uint64
  68. }
  69. func isMessageSigned(flags byte) bool {
  70. return (flags & signatureFlag) != 0
  71. }
  72. func (msg *ReceivedMessage) isSymmetricEncryption() bool {
  73. return msg.SymKeyHash != common.Hash{}
  74. }
  75. func (msg *ReceivedMessage) isAsymmetricEncryption() bool {
  76. return msg.Dst != nil
  77. }
  78. func DeriveOneTimeKey(key []byte, salt []byte, version uint64) ([]byte, error) {
  79. if version == 0 {
  80. derivedKey := pbkdf2.Key(key, salt, 8, aesKeyLength, sha256.New)
  81. return derivedKey, nil
  82. } else {
  83. return nil, unknownVersionError(version)
  84. }
  85. }
  86. // NewMessage creates and initializes a non-signed, non-encrypted Whisper message.
  87. func NewSentMessage(params *MessageParams) *SentMessage {
  88. msg := SentMessage{}
  89. msg.Raw = make([]byte, 1, len(params.Payload)+len(params.Payload)+signatureLength+padSizeLimitUpper)
  90. msg.Raw[0] = 0 // set all the flags to zero
  91. msg.appendPadding(params)
  92. msg.Raw = append(msg.Raw, params.Payload...)
  93. return &msg
  94. }
  95. // appendPadding appends the pseudorandom padding bytes and sets the padding flag.
  96. // The last byte contains the size of padding (thus, its size must not exceed 256).
  97. func (msg *SentMessage) appendPadding(params *MessageParams) {
  98. total := len(params.Payload) + 1
  99. if params.Src != nil {
  100. total += signatureLength
  101. }
  102. padChunk := padSizeLimitUpper
  103. if total <= padSizeLimitLower {
  104. padChunk = padSizeLimitLower
  105. }
  106. odd := total % padChunk
  107. if odd > 0 {
  108. padSize := padChunk - odd
  109. if padSize > 255 {
  110. // this algorithm is only valid if padSizeLimitUpper <= 256.
  111. // if padSizeLimitUpper will ever change, please fix the algorithm
  112. // (for more information see ReceivedMessage.extractPadding() function).
  113. panic("please fix the padding algorithm before releasing new version")
  114. }
  115. buf := make([]byte, padSize)
  116. randomize(buf[1:])
  117. buf[0] = byte(padSize)
  118. if params.Padding != nil {
  119. copy(buf[1:], params.Padding)
  120. }
  121. msg.Raw = append(msg.Raw, buf...)
  122. msg.Raw[0] |= byte(0x1) // number of bytes indicating the padding size
  123. }
  124. }
  125. // sign calculates and sets the cryptographic signature for the message,
  126. // also setting the sign flag.
  127. func (msg *SentMessage) sign(key *ecdsa.PrivateKey) error {
  128. if isMessageSigned(msg.Raw[0]) {
  129. // this should not happen, but no reason to panic
  130. glog.V(logger.Error).Infof("Trying to sign a message which was already signed")
  131. return nil
  132. }
  133. msg.Raw[0] |= signatureFlag
  134. hash := crypto.Keccak256(msg.Raw)
  135. signature, err := crypto.Sign(hash, key)
  136. if err != nil {
  137. msg.Raw[0] &= ^signatureFlag // clear the flag
  138. return err
  139. }
  140. msg.Raw = append(msg.Raw, signature...)
  141. return nil
  142. }
  143. // encryptAsymmetric encrypts a message with a public key.
  144. func (msg *SentMessage) encryptAsymmetric(key *ecdsa.PublicKey) error {
  145. if !ValidatePublicKey(key) {
  146. return fmt.Errorf("Invalid public key provided for asymmetric encryption")
  147. }
  148. encrypted, err := ecies.Encrypt(crand.Reader, ecies.ImportECDSAPublic(key), msg.Raw, nil, nil)
  149. if err == nil {
  150. msg.Raw = encrypted
  151. }
  152. return err
  153. }
  154. // encryptSymmetric encrypts a message with a topic key, using AES-GCM-256.
  155. // nonce size should be 12 bytes (see cipher.gcmStandardNonceSize).
  156. func (msg *SentMessage) encryptSymmetric(key []byte) (salt []byte, nonce []byte, err error) {
  157. if !validateSymmetricKey(key) {
  158. return nil, nil, errors.New("invalid key provided for symmetric encryption")
  159. }
  160. salt = make([]byte, saltLength)
  161. _, err = crand.Read(salt)
  162. if err != nil {
  163. return nil, nil, err
  164. } else if !validateSymmetricKey(salt) {
  165. return nil, nil, errors.New("crypto/rand failed to generate salt")
  166. }
  167. derivedKey, err := DeriveOneTimeKey(key, salt, EnvelopeVersion)
  168. if err != nil {
  169. return nil, nil, err
  170. }
  171. if !validateSymmetricKey(derivedKey) {
  172. return nil, nil, errors.New("failed to derive one-time key")
  173. }
  174. block, err := aes.NewCipher(derivedKey)
  175. if err != nil {
  176. return nil, nil, err
  177. }
  178. aesgcm, err := cipher.NewGCM(block)
  179. if err != nil {
  180. return nil, nil, err
  181. }
  182. // never use more than 2^32 random nonces with a given key
  183. nonce = make([]byte, aesgcm.NonceSize())
  184. _, err = crand.Read(nonce)
  185. if err != nil {
  186. return nil, nil, err
  187. } else if !validateSymmetricKey(nonce) {
  188. return nil, nil, errors.New("crypto/rand failed to generate nonce")
  189. }
  190. msg.Raw = aesgcm.Seal(nil, nonce, msg.Raw, nil)
  191. return salt, nonce, nil
  192. }
  193. // Wrap bundles the message into an Envelope to transmit over the network.
  194. //
  195. // pow (Proof Of Work) controls how much time to spend on hashing the message,
  196. // inherently controlling its priority through the network (smaller hash, bigger
  197. // priority).
  198. //
  199. // The user can control the amount of identity, privacy and encryption through
  200. // the options parameter as follows:
  201. // - options.From == nil && options.To == nil: anonymous broadcast
  202. // - options.From != nil && options.To == nil: signed broadcast (known sender)
  203. // - options.From == nil && options.To != nil: encrypted anonymous message
  204. // - options.From != nil && options.To != nil: encrypted signed message
  205. func (msg *SentMessage) Wrap(options *MessageParams) (envelope *Envelope, err error) {
  206. if options.TTL == 0 {
  207. options.TTL = DefaultTTL
  208. }
  209. if options.Src != nil {
  210. err = msg.sign(options.Src)
  211. if err != nil {
  212. return nil, err
  213. }
  214. }
  215. if len(msg.Raw) > MaxMessageLength {
  216. glog.V(logger.Error).Infof("Message size must not exceed %d bytes", MaxMessageLength)
  217. return nil, errors.New("Oversized message")
  218. }
  219. var salt, nonce []byte
  220. if options.Dst != nil {
  221. err = msg.encryptAsymmetric(options.Dst)
  222. } else if options.KeySym != nil {
  223. salt, nonce, err = msg.encryptSymmetric(options.KeySym)
  224. } else {
  225. err = errors.New("Unable to encrypt the message: neither Dst nor Key")
  226. }
  227. if err != nil {
  228. return nil, err
  229. }
  230. envelope = NewEnvelope(options.TTL, options.Topic, salt, nonce, msg)
  231. err = envelope.Seal(options)
  232. if 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, salt []byte, nonce []byte) error {
  240. derivedKey, err := DeriveOneTimeKey(key, salt, msg.EnvelopeVersion)
  241. if err != nil {
  242. return err
  243. }
  244. block, err := aes.NewCipher(derivedKey)
  245. if err != nil {
  246. return err
  247. }
  248. aesgcm, err := cipher.NewGCM(block)
  249. if err != nil {
  250. return err
  251. }
  252. if len(nonce) != aesgcm.NonceSize() {
  253. info := fmt.Sprintf("Wrong AES nonce size - want: %d, got: %d", len(nonce), aesgcm.NonceSize())
  254. glog.V(logger.Error).Infof(info)
  255. return errors.New(info)
  256. }
  257. decrypted, err := aesgcm.Open(nil, nonce, msg.Raw, nil)
  258. if err != nil {
  259. return err
  260. }
  261. msg.Raw = decrypted
  262. return nil
  263. }
  264. // decryptAsymmetric decrypts an encrypted payload with a private key.
  265. func (msg *ReceivedMessage) decryptAsymmetric(key *ecdsa.PrivateKey) error {
  266. decrypted, err := ecies.ImportECDSA(key).Decrypt(crand.Reader, msg.Raw, nil, nil)
  267. if err == nil {
  268. msg.Raw = decrypted
  269. }
  270. return err
  271. }
  272. // Validate checks the validity and extracts the fields in case of success
  273. func (msg *ReceivedMessage) Validate() bool {
  274. end := len(msg.Raw)
  275. if end < 1 {
  276. return false
  277. }
  278. if isMessageSigned(msg.Raw[0]) {
  279. end -= signatureLength
  280. if end <= 1 {
  281. return false
  282. }
  283. msg.Signature = msg.Raw[end:]
  284. msg.Src = msg.SigToPubKey()
  285. if msg.Src == nil {
  286. return false
  287. }
  288. }
  289. padSize, ok := msg.extractPadding(end)
  290. if !ok {
  291. return false
  292. }
  293. msg.Payload = msg.Raw[1+padSize : end]
  294. return true
  295. }
  296. // extractPadding extracts the padding from raw message.
  297. // although we don't support sending messages with padding size
  298. // exceeding 255 bytes, such messages are perfectly valid, and
  299. // can be successfully decrypted.
  300. func (msg *ReceivedMessage) extractPadding(end int) (int, bool) {
  301. paddingSize := 0
  302. sz := int(msg.Raw[0] & paddingMask) // number of bytes containing the entire size of padding, could be zero
  303. if sz != 0 {
  304. paddingSize = int(bytesToIntLittleEndian(msg.Raw[1 : 1+sz]))
  305. if paddingSize < sz || paddingSize+1 > end {
  306. return 0, false
  307. }
  308. msg.Padding = msg.Raw[1+sz : 1+paddingSize]
  309. }
  310. return paddingSize, true
  311. }
  312. // Recover retrieves the public key of the message signer.
  313. func (msg *ReceivedMessage) SigToPubKey() *ecdsa.PublicKey {
  314. defer func() { recover() }() // in case of invalid signature
  315. pub, err := crypto.SigToPub(msg.hash(), msg.Signature)
  316. if err != nil {
  317. glog.V(logger.Error).Infof("Could not get public key from signature: %v", err)
  318. return nil
  319. }
  320. return pub
  321. }
  322. // hash calculates the SHA3 checksum of the message flags, payload and padding.
  323. func (msg *ReceivedMessage) hash() []byte {
  324. if isMessageSigned(msg.Raw[0]) {
  325. sz := len(msg.Raw) - signatureLength
  326. return crypto.Keccak256(msg.Raw[:sz])
  327. }
  328. return crypto.Keccak256(msg.Raw)
  329. }
  330. // rand.Rand provides a Read method in Go 1.7 and later,
  331. // but we can't use it yet.
  332. func randomize(b []byte) {
  333. cnt := 0
  334. val := mrand.Int63()
  335. for n := 0; n < len(b); n++ {
  336. b[n] = byte(val)
  337. val >>= 8
  338. cnt++
  339. if cnt >= 7 {
  340. cnt = 0
  341. val = mrand.Int63()
  342. }
  343. }
  344. }