|
|
- package keys
-
- import (
- "encoding/binary"
- "errors"
- "hash/crc32"
- "hash/crc64"
-
- "github.com/howeyc/crc16"
- )
-
- // ECC is used for anything that calculates an error-correcting code
- type ECC interface {
- // AddECC calculates an error-correcting code for the input
- // returns an output with the code appended
- AddECC([]byte) []byte
-
- // CheckECC verifies if the ECC is proper on the input and returns
- // the data with the code removed, or an error
- CheckECC([]byte) ([]byte, error)
- }
-
- // NoECC is a no-op placeholder, kind of useless... except for tests
- type NoECC struct{}
-
- var _ ECC = NoECC{}
-
- func (_ NoECC) AddECC(input []byte) []byte { return input }
- func (_ NoECC) CheckECC(input []byte) ([]byte, error) { return input, nil }
-
- // CRC16 does the ieee crc16 polynomial check
- type CRC16 struct {
- Poly uint16
- table *crc16.Table
- }
-
- var _ ECC = &CRC16{}
-
- const crc16Size = 2
-
- func NewIBMCRC16() *CRC16 {
- return &CRC16{Poly: crc16.IBM}
- }
-
- func NewSCSICRC16() *CRC16 {
- return &CRC16{Poly: crc16.SCSI}
- }
-
- func NewCCITTCRC16() *CRC16 {
- return &CRC16{Poly: crc16.CCITT}
- }
-
- func (c *CRC16) AddECC(input []byte) []byte {
- table := c.getTable()
-
- // get crc and convert to some bytes...
- crc := crc16.Checksum(input, table)
- check := make([]byte, crc16Size)
- binary.BigEndian.PutUint16(check, crc)
-
- // append it to the input
- output := append(input, check...)
- return output
- }
-
- func (c *CRC16) CheckECC(input []byte) ([]byte, error) {
- table := c.getTable()
-
- if len(input) <= crc16Size {
- return nil, errors.New("input too short, no checksum present")
- }
- cut := len(input) - crc16Size
- data, check := input[:cut], input[cut:]
- crc := binary.BigEndian.Uint16(check)
- calc := crc16.Checksum(data, table)
- if crc != calc {
- return nil, errors.New("Checksum does not match")
- }
- return data, nil
- }
-
- func (c *CRC16) getTable() *crc16.Table {
- if c.table == nil {
- if c.Poly == 0 {
- c.Poly = crc16.IBM
- }
- c.table = crc16.MakeTable(c.Poly)
- }
- return c.table
- }
-
- // CRC32 does the ieee crc32 polynomial check
- type CRC32 struct {
- Poly uint32
- table *crc32.Table
- }
-
- var _ ECC = &CRC32{}
-
- func NewIEEECRC32() *CRC32 {
- return &CRC32{Poly: crc32.IEEE}
- }
-
- func NewCastagnoliCRC32() *CRC32 {
- return &CRC32{Poly: crc32.Castagnoli}
- }
-
- func NewKoopmanCRC32() *CRC32 {
- return &CRC32{Poly: crc32.Koopman}
- }
-
- func (c *CRC32) AddECC(input []byte) []byte {
- table := c.getTable()
-
- // get crc and convert to some bytes...
- crc := crc32.Checksum(input, table)
- check := make([]byte, crc32.Size)
- binary.BigEndian.PutUint32(check, crc)
-
- // append it to the input
- output := append(input, check...)
- return output
- }
-
- func (c *CRC32) CheckECC(input []byte) ([]byte, error) {
- table := c.getTable()
-
- if len(input) <= crc32.Size {
- return nil, errors.New("input too short, no checksum present")
- }
- cut := len(input) - crc32.Size
- data, check := input[:cut], input[cut:]
- crc := binary.BigEndian.Uint32(check)
- calc := crc32.Checksum(data, table)
- if crc != calc {
- return nil, errors.New("Checksum does not match")
- }
- return data, nil
- }
-
- func (c *CRC32) getTable() *crc32.Table {
- if c.table == nil {
- if c.Poly == 0 {
- c.Poly = crc32.IEEE
- }
- c.table = crc32.MakeTable(c.Poly)
- }
- return c.table
- }
-
- // CRC64 does the ieee crc64 polynomial check
- type CRC64 struct {
- Poly uint64
- table *crc64.Table
- }
-
- var _ ECC = &CRC64{}
-
- func NewISOCRC64() *CRC64 {
- return &CRC64{Poly: crc64.ISO}
- }
-
- func NewECMACRC64() *CRC64 {
- return &CRC64{Poly: crc64.ECMA}
- }
-
- func (c *CRC64) AddECC(input []byte) []byte {
- table := c.getTable()
-
- // get crc and convert to some bytes...
- crc := crc64.Checksum(input, table)
- check := make([]byte, crc64.Size)
- binary.BigEndian.PutUint64(check, crc)
-
- // append it to the input
- output := append(input, check...)
- return output
- }
-
- func (c *CRC64) CheckECC(input []byte) ([]byte, error) {
- table := c.getTable()
-
- if len(input) <= crc64.Size {
- return nil, errors.New("input too short, no checksum present")
- }
- cut := len(input) - crc64.Size
- data, check := input[:cut], input[cut:]
- crc := binary.BigEndian.Uint64(check)
- calc := crc64.Checksum(data, table)
- if crc != calc {
- return nil, errors.New("Checksum does not match")
- }
- return data, nil
- }
-
- func (c *CRC64) getTable() *crc64.Table {
- if c.table == nil {
- if c.Poly == 0 {
- c.Poly = crc64.ISO
- }
- c.table = crc64.MakeTable(c.Poly)
- }
- return c.table
- }
|