You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

208 lines
4.3 KiB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
  1. package keys
  2. import (
  3. "encoding/binary"
  4. "errors"
  5. "hash/crc32"
  6. "hash/crc64"
  7. "github.com/howeyc/crc16"
  8. )
  9. // ECC is used for anything that calculates an error-correcting code
  10. type ECC interface {
  11. // AddECC calculates an error-correcting code for the input
  12. // returns an output with the code appended
  13. AddECC([]byte) []byte
  14. // CheckECC verifies if the ECC is proper on the input and returns
  15. // the data with the code removed, or an error
  16. CheckECC([]byte) ([]byte, error)
  17. }
  18. var errInputTooShort = errors.New("input too short, no checksum present")
  19. var errChecksumDoesntMatch = errors.New("checksum does not match")
  20. // NoECC is a no-op placeholder, kind of useless... except for tests
  21. type NoECC struct{}
  22. var _ ECC = NoECC{}
  23. func (_ NoECC) AddECC(input []byte) []byte { return input }
  24. func (_ NoECC) CheckECC(input []byte) ([]byte, error) { return input, nil }
  25. // CRC16 does the ieee crc16 polynomial check
  26. type CRC16 struct {
  27. Poly uint16
  28. table *crc16.Table
  29. }
  30. var _ ECC = (*CRC16)(nil)
  31. const crc16ByteCount = 2
  32. func NewIBMCRC16() *CRC16 {
  33. return &CRC16{Poly: crc16.IBM}
  34. }
  35. func NewSCSICRC16() *CRC16 {
  36. return &CRC16{Poly: crc16.SCSI}
  37. }
  38. func NewCCITTCRC16() *CRC16 {
  39. return &CRC16{Poly: crc16.CCITT}
  40. }
  41. func (c *CRC16) AddECC(input []byte) []byte {
  42. table := c.getTable()
  43. // get crc and convert to some bytes...
  44. crc := crc16.Checksum(input, table)
  45. check := make([]byte, crc16ByteCount)
  46. binary.BigEndian.PutUint16(check, crc)
  47. // append it to the input
  48. output := append(input, check...)
  49. return output
  50. }
  51. func (c *CRC16) CheckECC(input []byte) ([]byte, error) {
  52. table := c.getTable()
  53. if len(input) <= crc16ByteCount {
  54. return nil, errInputTooShort
  55. }
  56. cut := len(input) - crc16ByteCount
  57. data, check := input[:cut], input[cut:]
  58. crc := binary.BigEndian.Uint16(check)
  59. calc := crc16.Checksum(data, table)
  60. if crc != calc {
  61. return nil, errChecksumDoesntMatch
  62. }
  63. return data, nil
  64. }
  65. func (c *CRC16) getTable() *crc16.Table {
  66. if c.table != nil {
  67. return c.table
  68. }
  69. if c.Poly == 0 {
  70. c.Poly = crc16.IBM
  71. }
  72. c.table = crc16.MakeTable(c.Poly)
  73. return c.table
  74. }
  75. // CRC32 does the ieee crc32 polynomial check
  76. type CRC32 struct {
  77. Poly uint32
  78. table *crc32.Table
  79. }
  80. var _ ECC = (*CRC32)(nil)
  81. func NewIEEECRC32() *CRC32 {
  82. return &CRC32{Poly: crc32.IEEE}
  83. }
  84. func NewCastagnoliCRC32() *CRC32 {
  85. return &CRC32{Poly: crc32.Castagnoli}
  86. }
  87. func NewKoopmanCRC32() *CRC32 {
  88. return &CRC32{Poly: crc32.Koopman}
  89. }
  90. func (c *CRC32) AddECC(input []byte) []byte {
  91. table := c.getTable()
  92. // get crc and convert to some bytes...
  93. crc := crc32.Checksum(input, table)
  94. check := make([]byte, crc32.Size)
  95. binary.BigEndian.PutUint32(check, crc)
  96. // append it to the input
  97. output := append(input, check...)
  98. return output
  99. }
  100. func (c *CRC32) CheckECC(input []byte) ([]byte, error) {
  101. table := c.getTable()
  102. if len(input) <= crc32.Size {
  103. return nil, errInputTooShort
  104. }
  105. cut := len(input) - crc32.Size
  106. data, check := input[:cut], input[cut:]
  107. crc := binary.BigEndian.Uint32(check)
  108. calc := crc32.Checksum(data, table)
  109. if crc != calc {
  110. return nil, errChecksumDoesntMatch
  111. }
  112. return data, nil
  113. }
  114. func (c *CRC32) getTable() *crc32.Table {
  115. if c.table == nil {
  116. if c.Poly == 0 {
  117. c.Poly = crc32.IEEE
  118. }
  119. c.table = crc32.MakeTable(c.Poly)
  120. }
  121. return c.table
  122. }
  123. // CRC64 does the ieee crc64 polynomial check
  124. type CRC64 struct {
  125. Poly uint64
  126. table *crc64.Table
  127. }
  128. var _ ECC = (*CRC64)(nil)
  129. func NewISOCRC64() *CRC64 {
  130. return &CRC64{Poly: crc64.ISO}
  131. }
  132. func NewECMACRC64() *CRC64 {
  133. return &CRC64{Poly: crc64.ECMA}
  134. }
  135. func (c *CRC64) AddECC(input []byte) []byte {
  136. table := c.getTable()
  137. // get crc and convert to some bytes...
  138. crc := crc64.Checksum(input, table)
  139. check := make([]byte, crc64.Size)
  140. binary.BigEndian.PutUint64(check, crc)
  141. // append it to the input
  142. output := append(input, check...)
  143. return output
  144. }
  145. func (c *CRC64) CheckECC(input []byte) ([]byte, error) {
  146. table := c.getTable()
  147. if len(input) <= crc64.Size {
  148. return nil, errInputTooShort
  149. }
  150. cut := len(input) - crc64.Size
  151. data, check := input[:cut], input[cut:]
  152. crc := binary.BigEndian.Uint64(check)
  153. calc := crc64.Checksum(data, table)
  154. if crc != calc {
  155. return nil, errChecksumDoesntMatch
  156. }
  157. return data, nil
  158. }
  159. func (c *CRC64) getTable() *crc64.Table {
  160. if c.table == nil {
  161. if c.Poly == 0 {
  162. c.Poly = crc64.ISO
  163. }
  164. c.table = crc64.MakeTable(c.Poly)
  165. }
  166. return c.table
  167. }