Guest User

Untitled

a guest
Nov 15th, 2018
77
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.36 KB | None | 0 0
  1. // This is an example message reader/writer with length prefixes and checksums
  2. // (in the example's case, using hmac-sha1) to try to confirm that the entire
  3. // correct message was read.
  4.  
  5. package main
  6.  
  7. import (
  8. "bytes"
  9. "crypto/hmac"
  10. "crypto/sha1"
  11. "encoding/binary"
  12. "errors"
  13. "fmt"
  14. "hash"
  15. "io"
  16. )
  17.  
  18. func main() {
  19. var b bytes.Buffer
  20.  
  21. var hasher HashFunc
  22. // CRC64:
  23. // isoTable := crc64.MakeTable(crc64.ISO)
  24. // hasher = HashFunc(func() hash.Hash { return crc64.New(isoTable) })
  25. // HMAC-SHA1:
  26. hasher = HMACFunc("key 1", sha1.New)
  27. // SHA1:
  28. // hasher = HashFunc(sha1.New)
  29. // No hash:
  30. // hasher = HashFunc(NullHash)
  31.  
  32. err := NewMessenger(100, binary.BigEndian, hasher).WriteMsg(&b, []byte("Hello, World"))
  33. if err != nil {
  34. panic(err)
  35. }
  36.  
  37. // Print written message
  38. fmt.Printf("BUF = %x\n", &b)
  39.  
  40. // Create hash mismatch:
  41. // hasher = hmacHashFunc("key 2", sha1.New)
  42.  
  43. msg, err := NewMessenger(100, binary.BigEndian, hasher).ReadMsg(&b)
  44. if err != nil {
  45. panic(err)
  46. }
  47.  
  48. // Print read message
  49. fmt.Printf("MSG = %q\n", msg)
  50. }
  51.  
  52. // HashFunc is a function that returns a new hash.Hash for use in a Messenger.
  53. // Returned hashes are not reused.
  54. type HashFunc func() hash.Hash
  55.  
  56. // Messenger reads and writes messages with length and checksum prefixes.
  57. type Messenger struct {
  58. hashfn HashFunc
  59. order binary.ByteOrder
  60. maxSize int64 // TODO: Consider using varints to avoid wasting a whole 8 bytes
  61. }
  62.  
  63. // NewMessenger allocates a new Messenger for reading and writing length-and-checksum prefixed
  64. // messages. maxMsgSize specifies the maximum size of a message in bytes, and must be greater than
  65. // eight bytes. If any arguments are invalid, NewMessenger panics.
  66. //
  67. // Returning an error would be more appropriate in real code, but this is a prototype.
  68. func NewMessenger(maxMsgSize int64, order binary.ByteOrder, hashfn HashFunc) *Messenger {
  69. if order == nil {
  70. panic("nil byte order")
  71. }
  72. if hashfn == nil {
  73. panic("nil hash constructor")
  74. }
  75. if maxMsgSize <= 8 {
  76. panic("max message size must be > 8 bytes")
  77. }
  78. return &Messenger{
  79. hashfn: hashfn,
  80. order: order,
  81. maxSize: maxMsgSize,
  82. }
  83. }
  84.  
  85. type msgHeader struct {
  86. Size int64
  87. Checksum []byte // Includes Size's bytes and the payload in it
  88. }
  89.  
  90. // ReadMsg reads length, checksum, and payload from r.
  91. // If the checksum of the payload does not match when filtered through Messenger's hash function, it
  92. // returns an error. This is to prevent acceptance of corrupt, spoofed, or otherwise invalid
  93. // messages (depending on the checksum).
  94. // In addition, too-small and too-large messages will also return errors.
  95. // All other errors arise from reading from r.
  96. func (m *Messenger) ReadMsg(r io.Reader) ([]byte, error) {
  97. h := m.hashfn()
  98. hashSize := h.Size()
  99. var header msgHeader
  100.  
  101. hashReader := io.TeeReader(r, h)
  102. if err := binary.Read(hashReader, m.order, &header.Size); err != nil {
  103. return nil, err
  104. }
  105.  
  106. headerSize := int64(hashSize)
  107. if header.Size > m.maxSize {
  108. return nil, fmt.Errorf("message of %d bytes exceeds max size of %d bytes", header.Size, m.maxSize)
  109. } else if header.Size <= headerSize {
  110. return nil, fmt.Errorf("message of %d bytes is too short", header.Size)
  111. }
  112.  
  113. header.Checksum = make([]byte, hashSize)
  114. if _, err := io.ReadFull(r, header.Checksum); err != nil {
  115. return nil, err
  116. }
  117.  
  118. p := make([]byte, int(header.Size-headerSize))
  119. _, err := io.ReadFull(hashReader, p)
  120. if err != nil {
  121. return nil, err
  122. }
  123.  
  124. if sum := h.Sum(nil); !hmac.Equal(sum, header.Checksum) {
  125. return nil, fmt.Errorf("message checksums don't match: sent(%x) <> received(%x)", sum, header.Checksum)
  126. }
  127.  
  128. return p, nil
  129. }
  130.  
  131. // WriteMsg writes the payload, p, prefixed by length and checksum, to the writer w.
  132. // If the length of p combined with the header's length would exceed the Messenger's maximum message
  133. // size, then the message is not written and an error is returned. Empty messages also return an
  134. // error. All other errors arise from writing to w.
  135. func (m *Messenger) WriteMsg(w io.Writer, p []byte) error {
  136. if len(p) == 0 {
  137. return errors.New("message is empty")
  138. }
  139.  
  140. h := m.hashfn()
  141. hashSize := h.Size()
  142. headerSize := int64(hashSize)
  143.  
  144. if int64(len(p)) > m.maxSize-headerSize {
  145. return fmt.Errorf("message of %d bytes exceeds max size of %d - header(%d) bytes", len(p), m.maxSize, headerSize)
  146. }
  147.  
  148. header := msgHeader{
  149. Size: int64(len(p)) + headerSize,
  150. Checksum: make([]byte, hashSize),
  151. }
  152.  
  153. if err := binary.Write(h, m.order, header.Size); err != nil {
  154. return err // This is probably unreachable.
  155. }
  156. h.Write(p)
  157. header.Checksum = h.Sum(header.Checksum[:0])
  158.  
  159. if err := binary.Write(w, m.order, header.Size); err != nil {
  160. return err
  161. }
  162.  
  163. if n, err := w.Write(header.Checksum); err != nil {
  164. return err
  165. } else if n != len(header.Checksum) {
  166. // NB: This doesn't handle the strange case of n > len() politely
  167. return io.ErrShortWrite
  168. }
  169.  
  170. if n, err := w.Write(p); err != nil {
  171. return err
  172. } else if n != len(p) {
  173. return io.ErrShortWrite
  174. }
  175.  
  176. return nil
  177. }
  178.  
  179. // Hash functions for testing:
  180.  
  181. func HMACFunc(key string, hashfn HashFunc) HashFunc {
  182. bkey := []byte(key)
  183. return func() hash.Hash {
  184. return hmac.New(hashfn, bkey)
  185. }
  186. }
  187.  
  188. func NullHash() hash.Hash {
  189. return nullHasher{}
  190. }
  191.  
  192. type nullHasher struct{}
  193.  
  194. func (nullHasher) Write(p []byte) (n int, err error) {
  195. return len(p), nil
  196. }
  197.  
  198. func (nullHasher) Size() int { return 0 }
  199. func (nullHasher) Reset() {}
  200. func (nullHasher) BlockSize() int { return 1 }
  201. func (nullHasher) Sum(h []byte) []byte { return h[:0] }
Add Comment
Please, Sign In to add comment