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.

204 lines
4.2 KiB

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