Mifare Classic RFID tag dump: Go parsing library

You can get a dump for testing from this link: https://github.com/zhovner/mfdread/raw/master/dump.mfd

File extension

mfd

KS implementation details

License: BSD-2-Clause
Minimal Kaitai Struct required: 0.9

References

This page hosts a formal specification of Mifare Classic RFID tag dump using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Go source code to parse Mifare Classic RFID tag dump

mifare_classic.go

// Code generated by kaitai-struct-compiler from a .ksy source file. DO NOT EDIT.

import (
	"github.com/kaitai-io/kaitai_struct_go_runtime/kaitai"
	"bytes"
	"io"
)


/**
 * You can get a dump for testing from this link:
 * <https://github.com/zhovner/mfdread/raw/master/dump.mfd>
 * @see <a href="https://github.com/nfc-tools/libnfc
 * https://www.nxp.com/docs/en/data-sheet/MF1S70YYX_V1.pdf
 * ">Source</a>
 */
type MifareClassic struct {
	Sectors []*MifareClassic_Sector
	_io *kaitai.Stream
	_root *MifareClassic
	_parent kaitai.Struct
	_raw_Sectors [][]byte
}
func NewMifareClassic() *MifareClassic {
	return &MifareClassic{
	}
}

func (this MifareClassic) IO_() *kaitai.Stream {
	return this._io
}

func (this *MifareClassic) Read(io *kaitai.Stream, parent kaitai.Struct, root *MifareClassic) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	for i := 0;; i++ {
		tmp1, err := this._io.EOF()
		if err != nil {
			return err
		}
		if tmp1 {
			break
		}
		var tmp2 int8;
		if (i >= 32) {
			tmp2 = 4
		} else {
			tmp2 = 1
		}
		tmp3, err := this._io.ReadBytes(int((tmp2 * 4) * 16))
		if err != nil {
			return err
		}
		tmp3 = tmp3
		this._raw_Sectors = append(this._raw_Sectors, tmp3)
		_io__raw_Sectors := kaitai.NewStream(bytes.NewReader(this._raw_Sectors[len(this._raw_Sectors) - 1]))
		tmp4 := NewMifareClassic_Sector(i == 0)
		err = tmp4.Read(_io__raw_Sectors, this, this._root)
		if err != nil {
			return err
		}
		this.Sectors = append(this.Sectors, tmp4)
	}
	return err
}
type MifareClassic_Key struct {
	Key []byte
	_io *kaitai.Stream
	_root *MifareClassic
	_parent *MifareClassic_Trailer
}
func NewMifareClassic_Key() *MifareClassic_Key {
	return &MifareClassic_Key{
	}
}

func (this MifareClassic_Key) IO_() *kaitai.Stream {
	return this._io
}

func (this *MifareClassic_Key) Read(io *kaitai.Stream, parent *MifareClassic_Trailer, root *MifareClassic) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp5, err := this._io.ReadBytes(int(6))
	if err != nil {
		return err
	}
	tmp5 = tmp5
	this.Key = tmp5
	return err
}
type MifareClassic_Manufacturer struct {
	Nuid uint32
	Bcc uint8
	Sak uint8
	Atqa uint16
	Manufacturer []byte
	_io *kaitai.Stream
	_root *MifareClassic
	_parent *MifareClassic_Sector
}
func NewMifareClassic_Manufacturer() *MifareClassic_Manufacturer {
	return &MifareClassic_Manufacturer{
	}
}

func (this MifareClassic_Manufacturer) IO_() *kaitai.Stream {
	return this._io
}

func (this *MifareClassic_Manufacturer) Read(io *kaitai.Stream, parent *MifareClassic_Sector, root *MifareClassic) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp6, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.Nuid = uint32(tmp6)
	tmp7, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.Bcc = tmp7
	tmp8, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.Sak = tmp8
	tmp9, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.Atqa = uint16(tmp9)
	tmp10, err := this._io.ReadBytes(int(8))
	if err != nil {
		return err
	}
	tmp10 = tmp10
	this.Manufacturer = tmp10
	return err
}

/**
 * beware for 7bytes UID it goes over next fields
 */

/**
 * may contain manufacture date as BCD
 */
type MifareClassic_Sector struct {
	Manufacturer *MifareClassic_Manufacturer
	DataFiller *MifareClassic_Sector_Filler
	Trailer *MifareClassic_Trailer
	HasManufacturer bool
	_io *kaitai.Stream
	_root *MifareClassic
	_parent *MifareClassic
	_raw_DataFiller []byte
	_f_blockSize bool
	blockSize int8
	_f_blocks bool
	blocks [][]byte
	_f_data bool
	data []byte
	_f_values bool
	values *MifareClassic_Sector_Values
}
func NewMifareClassic_Sector(hasManufacturer bool) *MifareClassic_Sector {
	return &MifareClassic_Sector{
		HasManufacturer: hasManufacturer,
	}
}

func (this MifareClassic_Sector) IO_() *kaitai.Stream {
	return this._io
}

func (this *MifareClassic_Sector) Read(io *kaitai.Stream, parent *MifareClassic, root *MifareClassic) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	if (this.HasManufacturer) {
		tmp11 := NewMifareClassic_Manufacturer()
		err = tmp11.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Manufacturer = tmp11
	}
	tmp12, err := this._io.Size()
	if err != nil {
		return err
	}
	tmp13, err := this._io.Pos()
	if err != nil {
		return err
	}
	tmp14, err := this._io.ReadBytes(int((tmp12 - tmp13) - 16))
	if err != nil {
		return err
	}
	tmp14 = tmp14
	this._raw_DataFiller = tmp14
	_io__raw_DataFiller := kaitai.NewStream(bytes.NewReader(this._raw_DataFiller))
	tmp15 := NewMifareClassic_Sector_Filler()
	err = tmp15.Read(_io__raw_DataFiller, this, this._root)
	if err != nil {
		return err
	}
	this.DataFiller = tmp15
	tmp16 := NewMifareClassic_Trailer()
	err = tmp16.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.Trailer = tmp16
	return err
}
func (this *MifareClassic_Sector) BlockSize() (v int8, err error) {
	if (this._f_blockSize) {
		return this.blockSize, nil
	}
	this._f_blockSize = true
	this.blockSize = int8(16)
	return this.blockSize, nil
}
func (this *MifareClassic_Sector) Blocks() (v [][]byte, err error) {
	if (this._f_blocks) {
		return this.blocks, nil
	}
	this._f_blocks = true
	thisIo := this.DataFiller._io
	_pos, err := thisIo.Pos()
	if err != nil {
		return nil, err
	}
	_, err = thisIo.Seek(int64(0), io.SeekStart)
	if err != nil {
		return nil, err
	}
	for i := 0;; i++ {
		tmp17, err := this._io.EOF()
		if err != nil {
			return nil, err
		}
		if tmp17 {
			break
		}
		tmp18, err := this.BlockSize()
		if err != nil {
			return nil, err
		}
		tmp19, err := thisIo.ReadBytes(int(tmp18))
		if err != nil {
			return nil, err
		}
		tmp19 = tmp19
		this.blocks = append(this.blocks, tmp19)
	}
	_, err = thisIo.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	return this.blocks, nil
}
func (this *MifareClassic_Sector) Data() (v []byte, err error) {
	if (this._f_data) {
		return this.data, nil
	}
	this._f_data = true
	this.data = []byte(this.DataFiller.Data)
	return this.data, nil
}
func (this *MifareClassic_Sector) Values() (v *MifareClassic_Sector_Values, err error) {
	if (this._f_values) {
		return this.values, nil
	}
	this._f_values = true
	thisIo := this.DataFiller._io
	_pos, err := thisIo.Pos()
	if err != nil {
		return nil, err
	}
	_, err = thisIo.Seek(int64(0), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp20 := NewMifareClassic_Sector_Values()
	err = tmp20.Read(thisIo, this, this._root)
	if err != nil {
		return nil, err
	}
	this.values = tmp20
	_, err = thisIo.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	return this.values, nil
}

/**
 * only to create _io
 */
type MifareClassic_Sector_Filler struct {
	Data []byte
	_io *kaitai.Stream
	_root *MifareClassic
	_parent *MifareClassic_Sector
}
func NewMifareClassic_Sector_Filler() *MifareClassic_Sector_Filler {
	return &MifareClassic_Sector_Filler{
	}
}

func (this MifareClassic_Sector_Filler) IO_() *kaitai.Stream {
	return this._io
}

func (this *MifareClassic_Sector_Filler) Read(io *kaitai.Stream, parent *MifareClassic_Sector, root *MifareClassic) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp21, err := this._io.Size()
	if err != nil {
		return err
	}
	tmp22, err := this._io.ReadBytes(int(tmp21))
	if err != nil {
		return err
	}
	tmp22 = tmp22
	this.Data = tmp22
	return err
}
type MifareClassic_Sector_Values struct {
	Values []*MifareClassic_Sector_Values_ValueBlock
	_io *kaitai.Stream
	_root *MifareClassic
	_parent *MifareClassic_Sector
}
func NewMifareClassic_Sector_Values() *MifareClassic_Sector_Values {
	return &MifareClassic_Sector_Values{
	}
}

func (this MifareClassic_Sector_Values) IO_() *kaitai.Stream {
	return this._io
}

func (this *MifareClassic_Sector_Values) Read(io *kaitai.Stream, parent *MifareClassic_Sector, root *MifareClassic) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	for i := 0;; i++ {
		tmp23, err := this._io.EOF()
		if err != nil {
			return err
		}
		if tmp23 {
			break
		}
		tmp24 := NewMifareClassic_Sector_Values_ValueBlock()
		err = tmp24.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Values = append(this.Values, tmp24)
	}
	return err
}
type MifareClassic_Sector_Values_ValueBlock struct {
	Valuez []uint32
	Addrz []uint8
	_io *kaitai.Stream
	_root *MifareClassic
	_parent *MifareClassic_Sector_Values
	_f_addr bool
	addr uint8
	_f_addrValid bool
	addrValid bool
	_f_valid bool
	valid bool
	_f_value bool
	value uint32
	_f_valueValid bool
	valueValid bool
}
func NewMifareClassic_Sector_Values_ValueBlock() *MifareClassic_Sector_Values_ValueBlock {
	return &MifareClassic_Sector_Values_ValueBlock{
	}
}

func (this MifareClassic_Sector_Values_ValueBlock) IO_() *kaitai.Stream {
	return this._io
}

func (this *MifareClassic_Sector_Values_ValueBlock) Read(io *kaitai.Stream, parent *MifareClassic_Sector_Values, root *MifareClassic) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	for i := 0; i < int(3); i++ {
		_ = i
		tmp25, err := this._io.ReadU4le()
		if err != nil {
			return err
		}
		this.Valuez = append(this.Valuez, tmp25)
	}
	for i := 0; i < int(4); i++ {
		_ = i
		tmp26, err := this._io.ReadU1()
		if err != nil {
			return err
		}
		this.Addrz = append(this.Addrz, tmp26)
	}
	return err
}
func (this *MifareClassic_Sector_Values_ValueBlock) Addr() (v uint8, err error) {
	if (this._f_addr) {
		return this.addr, nil
	}
	this._f_addr = true
	tmp27, err := this.Valid()
	if err != nil {
		return 0, err
	}
	if (tmp27) {
		this.addr = uint8(this.Addrz[0])
	}
	return this.addr, nil
}
func (this *MifareClassic_Sector_Values_ValueBlock) AddrValid() (v bool, err error) {
	if (this._f_addrValid) {
		return this.addrValid, nil
	}
	this._f_addrValid = true
	this.addrValid = bool( ((this.Addrz[0] == ^(this.Addrz[1])) && (this.Addrz[0] == this.Addrz[2]) && (this.Addrz[1] == this.Addrz[3])) )
	return this.addrValid, nil
}
func (this *MifareClassic_Sector_Values_ValueBlock) Valid() (v bool, err error) {
	if (this._f_valid) {
		return this.valid, nil
	}
	this._f_valid = true
	tmp28, err := this.ValueValid()
	if err != nil {
		return false, err
	}
	tmp29, err := this.AddrValid()
	if err != nil {
		return false, err
	}
	this.valid = bool( ((tmp28) && (tmp29)) )
	return this.valid, nil
}
func (this *MifareClassic_Sector_Values_ValueBlock) Value() (v uint32, err error) {
	if (this._f_value) {
		return this.value, nil
	}
	this._f_value = true
	tmp30, err := this.Valid()
	if err != nil {
		return 0, err
	}
	if (tmp30) {
		this.value = uint32(this.Valuez[0])
	}
	return this.value, nil
}
func (this *MifareClassic_Sector_Values_ValueBlock) ValueValid() (v bool, err error) {
	if (this._f_valueValid) {
		return this.valueValid, nil
	}
	this._f_valueValid = true
	this.valueValid = bool( ((this.Valuez[0] == ^(this.Valuez[1])) && (this.Valuez[0] == this.Valuez[2])) )
	return this.valueValid, nil
}
type MifareClassic_Trailer struct {
	KeyA *MifareClassic_Key
	AccessBits *MifareClassic_Trailer_AccessConditions
	UserByte uint8
	KeyB *MifareClassic_Key
	_io *kaitai.Stream
	_root *MifareClassic
	_parent *MifareClassic_Sector
	_raw_AccessBits []byte
	_f_acBits bool
	acBits int8
	_f_acCountOfChunks bool
	acCountOfChunks int
	_f_acsInSector bool
	acsInSector int8
}
func NewMifareClassic_Trailer() *MifareClassic_Trailer {
	return &MifareClassic_Trailer{
	}
}

func (this MifareClassic_Trailer) IO_() *kaitai.Stream {
	return this._io
}

func (this *MifareClassic_Trailer) Read(io *kaitai.Stream, parent *MifareClassic_Sector, root *MifareClassic) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp31 := NewMifareClassic_Key()
	err = tmp31.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.KeyA = tmp31
	tmp32, err := this._io.ReadBytes(int(3))
	if err != nil {
		return err
	}
	tmp32 = tmp32
	this._raw_AccessBits = tmp32
	_io__raw_AccessBits := kaitai.NewStream(bytes.NewReader(this._raw_AccessBits))
	tmp33 := NewMifareClassic_Trailer_AccessConditions()
	err = tmp33.Read(_io__raw_AccessBits, this, this._root)
	if err != nil {
		return err
	}
	this.AccessBits = tmp33
	tmp34, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.UserByte = tmp34
	tmp35 := NewMifareClassic_Key()
	err = tmp35.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.KeyB = tmp35
	return err
}
func (this *MifareClassic_Trailer) AcBits() (v int8, err error) {
	if (this._f_acBits) {
		return this.acBits, nil
	}
	this._f_acBits = true
	this.acBits = int8(3)
	return this.acBits, nil
}
func (this *MifareClassic_Trailer) AcCountOfChunks() (v int, err error) {
	if (this._f_acCountOfChunks) {
		return this.acCountOfChunks, nil
	}
	this._f_acCountOfChunks = true
	tmp36, err := this.AcBits()
	if err != nil {
		return 0, err
	}
	this.acCountOfChunks = int(tmp36 * 2)
	return this.acCountOfChunks, nil
}
func (this *MifareClassic_Trailer) AcsInSector() (v int8, err error) {
	if (this._f_acsInSector) {
		return this.acsInSector, nil
	}
	this._f_acsInSector = true
	this.acsInSector = int8(4)
	return this.acsInSector, nil
}
type MifareClassic_Trailer_AccessConditions struct {
	RawChunks []uint64
	_io *kaitai.Stream
	_root *MifareClassic
	_parent *MifareClassic_Trailer
	_f_acsRaw bool
	acsRaw []*MifareClassic_Trailer_AccessConditions_Ac
	_f_chunks bool
	chunks []*MifareClassic_Trailer_AccessConditions_ValidChunk
	_f_dataAcs bool
	dataAcs []*MifareClassic_Trailer_AccessConditions_DataAc
	_f_remaps bool
	remaps []*MifareClassic_Trailer_AccessConditions_ChunkBitRemap
	_f_trailerAc bool
	trailerAc *MifareClassic_Trailer_AccessConditions_TrailerAc
}
func NewMifareClassic_Trailer_AccessConditions() *MifareClassic_Trailer_AccessConditions {
	return &MifareClassic_Trailer_AccessConditions{
	}
}

func (this MifareClassic_Trailer_AccessConditions) IO_() *kaitai.Stream {
	return this._io
}

func (this *MifareClassic_Trailer_AccessConditions) Read(io *kaitai.Stream, parent *MifareClassic_Trailer, root *MifareClassic) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp37, err := this._parent.AcCountOfChunks()
	if err != nil {
		return err
	}
	for i := 0; i < int(tmp37); i++ {
		_ = i
		tmp38, err := this._io.ReadBitsIntBe(4)
		if err != nil {
			return err
		}
		this.RawChunks = append(this.RawChunks, tmp38)
	}
	return err
}
func (this *MifareClassic_Trailer_AccessConditions) AcsRaw() (v []*MifareClassic_Trailer_AccessConditions_Ac, err error) {
	if (this._f_acsRaw) {
		return this.acsRaw, nil
	}
	this._f_acsRaw = true
	_pos, err := this._io.Pos()
	if err != nil {
		return nil, err
	}
	_, err = this._io.Seek(int64(0), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp39, err := this._parent.AcsInSector()
	if err != nil {
		return nil, err
	}
	for i := 0; i < int(tmp39); i++ {
		_ = i
		tmp40 := NewMifareClassic_Trailer_AccessConditions_Ac(i)
		err = tmp40.Read(this._io, this, this._root)
		if err != nil {
			return nil, err
		}
		this.acsRaw = append(this.acsRaw, tmp40)
	}
	_, err = this._io.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	return this.acsRaw, nil
}
func (this *MifareClassic_Trailer_AccessConditions) Chunks() (v []*MifareClassic_Trailer_AccessConditions_ValidChunk, err error) {
	if (this._f_chunks) {
		return this.chunks, nil
	}
	this._f_chunks = true
	_pos, err := this._io.Pos()
	if err != nil {
		return nil, err
	}
	_, err = this._io.Seek(int64(0), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp41, err := this._parent.AcBits()
	if err != nil {
		return nil, err
	}
	for i := 0; i < int(tmp41); i++ {
		_ = i
		tmp42, err := this.Remaps()
		if err != nil {
			return nil, err
		}
		tmp43, err := tmp42[i].InvChunkNo()
		if err != nil {
			return nil, err
		}
		tmp44, err := this.Remaps()
		if err != nil {
			return nil, err
		}
		tmp45, err := tmp44[i].ChunkNo()
		if err != nil {
			return nil, err
		}
		tmp46 := NewMifareClassic_Trailer_AccessConditions_ValidChunk(this.RawChunks[tmp43], this.RawChunks[tmp45])
		err = tmp46.Read(this._io, this, this._root)
		if err != nil {
			return nil, err
		}
		this.chunks = append(this.chunks, tmp46)
	}
	_, err = this._io.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	return this.chunks, nil
}
func (this *MifareClassic_Trailer_AccessConditions) DataAcs() (v []*MifareClassic_Trailer_AccessConditions_DataAc, err error) {
	if (this._f_dataAcs) {
		return this.dataAcs, nil
	}
	this._f_dataAcs = true
	_pos, err := this._io.Pos()
	if err != nil {
		return nil, err
	}
	_, err = this._io.Seek(int64(0), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp47, err := this._parent.AcsInSector()
	if err != nil {
		return nil, err
	}
	for i := 0; i < int(tmp47 - 1); i++ {
		_ = i
		tmp48, err := this.AcsRaw()
		if err != nil {
			return nil, err
		}
		tmp49 := NewMifareClassic_Trailer_AccessConditions_DataAc(tmp48[i])
		err = tmp49.Read(this._io, this, this._root)
		if err != nil {
			return nil, err
		}
		this.dataAcs = append(this.dataAcs, tmp49)
	}
	_, err = this._io.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	return this.dataAcs, nil
}
func (this *MifareClassic_Trailer_AccessConditions) Remaps() (v []*MifareClassic_Trailer_AccessConditions_ChunkBitRemap, err error) {
	if (this._f_remaps) {
		return this.remaps, nil
	}
	this._f_remaps = true
	_pos, err := this._io.Pos()
	if err != nil {
		return nil, err
	}
	_, err = this._io.Seek(int64(0), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp50, err := this._parent.AcBits()
	if err != nil {
		return nil, err
	}
	for i := 0; i < int(tmp50); i++ {
		_ = i
		tmp51 := NewMifareClassic_Trailer_AccessConditions_ChunkBitRemap(i)
		err = tmp51.Read(this._io, this, this._root)
		if err != nil {
			return nil, err
		}
		this.remaps = append(this.remaps, tmp51)
	}
	_, err = this._io.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	return this.remaps, nil
}
func (this *MifareClassic_Trailer_AccessConditions) TrailerAc() (v *MifareClassic_Trailer_AccessConditions_TrailerAc, err error) {
	if (this._f_trailerAc) {
		return this.trailerAc, nil
	}
	this._f_trailerAc = true
	_pos, err := this._io.Pos()
	if err != nil {
		return nil, err
	}
	_, err = this._io.Seek(int64(0), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp52, err := this.AcsRaw()
	if err != nil {
		return nil, err
	}
	tmp53, err := this._parent.AcsInSector()
	if err != nil {
		return nil, err
	}
	tmp54 := NewMifareClassic_Trailer_AccessConditions_TrailerAc(tmp52[tmp53 - 1])
	err = tmp54.Read(this._io, this, this._root)
	if err != nil {
		return nil, err
	}
	this.trailerAc = tmp54
	_, err = this._io.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	return this.trailerAc, nil
}
type MifareClassic_Trailer_AccessConditions_Ac struct {
	Index uint8
	_io *kaitai.Stream
	_root *MifareClassic
	_parent *MifareClassic_Trailer_AccessConditions
	_f_bits bool
	bits []*MifareClassic_Trailer_AccessConditions_Ac_AcBit
	_f_invShiftVal bool
	invShiftVal int
	_f_val bool
	val int
}
func NewMifareClassic_Trailer_AccessConditions_Ac(index uint8) *MifareClassic_Trailer_AccessConditions_Ac {
	return &MifareClassic_Trailer_AccessConditions_Ac{
		Index: index,
	}
}

func (this MifareClassic_Trailer_AccessConditions_Ac) IO_() *kaitai.Stream {
	return this._io
}

func (this *MifareClassic_Trailer_AccessConditions_Ac) Read(io *kaitai.Stream, parent *MifareClassic_Trailer_AccessConditions, root *MifareClassic) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	return err
}
func (this *MifareClassic_Trailer_AccessConditions_Ac) Bits() (v []*MifareClassic_Trailer_AccessConditions_Ac_AcBit, err error) {
	if (this._f_bits) {
		return this.bits, nil
	}
	this._f_bits = true
	_pos, err := this._io.Pos()
	if err != nil {
		return nil, err
	}
	_, err = this._io.Seek(int64(0), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp55, err := this._parent._parent.AcBits()
	if err != nil {
		return nil, err
	}
	for i := 0; i < int(tmp55); i++ {
		_ = i
		tmp56, err := this._parent.Chunks()
		if err != nil {
			return nil, err
		}
		tmp57 := NewMifareClassic_Trailer_AccessConditions_Ac_AcBit(this.Index, tmp56[i].Chunk)
		err = tmp57.Read(this._io, this, this._root)
		if err != nil {
			return nil, err
		}
		this.bits = append(this.bits, tmp57)
	}
	_, err = this._io.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	return this.bits, nil
}
func (this *MifareClassic_Trailer_AccessConditions_Ac) InvShiftVal() (v int, err error) {
	if (this._f_invShiftVal) {
		return this.invShiftVal, nil
	}
	this._f_invShiftVal = true
	tmp58, err := this.Bits()
	if err != nil {
		return 0, err
	}
	tmp59, err := tmp58[0].N()
	if err != nil {
		return 0, err
	}
	tmp60, err := this.Bits()
	if err != nil {
		return 0, err
	}
	tmp61, err := tmp60[1].N()
	if err != nil {
		return 0, err
	}
	tmp62, err := this.Bits()
	if err != nil {
		return 0, err
	}
	tmp63, err := tmp62[2].N()
	if err != nil {
		return 0, err
	}
	this.invShiftVal = int((tmp59 << 2 | tmp61 << 1) | tmp63)
	return this.invShiftVal, nil
}

/**
 * c3 c2 c1
 */
func (this *MifareClassic_Trailer_AccessConditions_Ac) Val() (v int, err error) {
	if (this._f_val) {
		return this.val, nil
	}
	this._f_val = true
	tmp64, err := this.Bits()
	if err != nil {
		return 0, err
	}
	tmp65, err := tmp64[2].N()
	if err != nil {
		return 0, err
	}
	tmp66, err := this.Bits()
	if err != nil {
		return 0, err
	}
	tmp67, err := tmp66[1].N()
	if err != nil {
		return 0, err
	}
	tmp68, err := this.Bits()
	if err != nil {
		return 0, err
	}
	tmp69, err := tmp68[0].N()
	if err != nil {
		return 0, err
	}
	this.val = int((tmp65 << 2 | tmp67 << 1) | tmp69)
	return this.val, nil
}
type MifareClassic_Trailer_AccessConditions_Ac_AcBit struct {
	I uint8
	Chunk uint8
	_io *kaitai.Stream
	_root *MifareClassic
	_parent *MifareClassic_Trailer_AccessConditions_Ac
	_f_b bool
	b bool
	_f_n bool
	n int
}
func NewMifareClassic_Trailer_AccessConditions_Ac_AcBit(i uint8, chunk uint8) *MifareClassic_Trailer_AccessConditions_Ac_AcBit {
	return &MifareClassic_Trailer_AccessConditions_Ac_AcBit{
		I: i,
		Chunk: chunk,
	}
}

func (this MifareClassic_Trailer_AccessConditions_Ac_AcBit) IO_() *kaitai.Stream {
	return this._io
}

func (this *MifareClassic_Trailer_AccessConditions_Ac_AcBit) Read(io *kaitai.Stream, parent *MifareClassic_Trailer_AccessConditions_Ac, root *MifareClassic) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	return err
}
func (this *MifareClassic_Trailer_AccessConditions_Ac_AcBit) B() (v bool, err error) {
	if (this._f_b) {
		return this.b, nil
	}
	this._f_b = true
	tmp70, err := this.N()
	if err != nil {
		return false, err
	}
	this.b = bool(tmp70 == 1)
	return this.b, nil
}
func (this *MifareClassic_Trailer_AccessConditions_Ac_AcBit) N() (v int, err error) {
	if (this._f_n) {
		return this.n, nil
	}
	this._f_n = true
	this.n = int((this.Chunk >> this.I) & 1)
	return this.n, nil
}
type MifareClassic_Trailer_AccessConditions_ChunkBitRemap struct {
	BitNo uint8
	_io *kaitai.Stream
	_root *MifareClassic
	_parent *MifareClassic_Trailer_AccessConditions
	_f_chunkNo bool
	chunkNo int
	_f_invChunkNo bool
	invChunkNo int
	_f_shiftValue bool
	shiftValue int
}
func NewMifareClassic_Trailer_AccessConditions_ChunkBitRemap(bitNo uint8) *MifareClassic_Trailer_AccessConditions_ChunkBitRemap {
	return &MifareClassic_Trailer_AccessConditions_ChunkBitRemap{
		BitNo: bitNo,
	}
}

func (this MifareClassic_Trailer_AccessConditions_ChunkBitRemap) IO_() *kaitai.Stream {
	return this._io
}

func (this *MifareClassic_Trailer_AccessConditions_ChunkBitRemap) Read(io *kaitai.Stream, parent *MifareClassic_Trailer_AccessConditions, root *MifareClassic) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	return err
}
func (this *MifareClassic_Trailer_AccessConditions_ChunkBitRemap) ChunkNo() (v int, err error) {
	if (this._f_chunkNo) {
		return this.chunkNo, nil
	}
	this._f_chunkNo = true
	tmp72, err := this.InvChunkNo()
	if err != nil {
		return 0, err
	}
	tmp73, err := this.ShiftValue()
	if err != nil {
		return 0, err
	}
	tmp74, err := this._parent._parent.AcCountOfChunks()
	if err != nil {
		return 0, err
	}
	tmp75, err := this._parent._parent.AcCountOfChunks()
	if err != nil {
		return 0, err
	}
	tmp71 := ((tmp72 + tmp73) + tmp74) % tmp75
	if tmp71 < 0 {
		tmp76, err := this._parent._parent.AcCountOfChunks()
		if err != nil {
			return 0, err
		}
		tmp71 += tmp76
	}
	this.chunkNo = int(tmp71)
	return this.chunkNo, nil
}
func (this *MifareClassic_Trailer_AccessConditions_ChunkBitRemap) InvChunkNo() (v int, err error) {
	if (this._f_invChunkNo) {
		return this.invChunkNo, nil
	}
	this._f_invChunkNo = true
	tmp77, err := this.ShiftValue()
	if err != nil {
		return 0, err
	}
	this.invChunkNo = int(this.BitNo + tmp77)
	return this.invChunkNo, nil
}
func (this *MifareClassic_Trailer_AccessConditions_ChunkBitRemap) ShiftValue() (v int, err error) {
	if (this._f_shiftValue) {
		return this.shiftValue, nil
	}
	this._f_shiftValue = true
	var tmp78 int;
	if (this.BitNo == 1) {
		tmp78 = -1
	} else {
		tmp78 = 1
	}
	this.shiftValue = int(tmp78)
	return this.shiftValue, nil
}
type MifareClassic_Trailer_AccessConditions_DataAc struct {
	Ac *MifareClassic_Trailer_AccessConditions_Ac
	_io *kaitai.Stream
	_root *MifareClassic
	_parent *MifareClassic_Trailer_AccessConditions
	_f_decrementAvailable bool
	decrementAvailable bool
	_f_incrementAvailable bool
	incrementAvailable bool
	_f_readKeyARequired bool
	readKeyARequired bool
	_f_readKeyBRequired bool
	readKeyBRequired bool
	_f_writeKeyARequired bool
	writeKeyARequired bool
	_f_writeKeyBRequired bool
	writeKeyBRequired bool
}
func NewMifareClassic_Trailer_AccessConditions_DataAc(ac *MifareClassic_Trailer_AccessConditions_Ac) *MifareClassic_Trailer_AccessConditions_DataAc {
	return &MifareClassic_Trailer_AccessConditions_DataAc{
		Ac: ac,
	}
}

func (this MifareClassic_Trailer_AccessConditions_DataAc) IO_() *kaitai.Stream {
	return this._io
}

func (this *MifareClassic_Trailer_AccessConditions_DataAc) Read(io *kaitai.Stream, parent *MifareClassic_Trailer_AccessConditions, root *MifareClassic) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	return err
}
func (this *MifareClassic_Trailer_AccessConditions_DataAc) DecrementAvailable() (v bool, err error) {
	if (this._f_decrementAvailable) {
		return this.decrementAvailable, nil
	}
	this._f_decrementAvailable = true
	tmp79, err := this.Ac.Bits()
	if err != nil {
		return false, err
	}
	tmp80, err := tmp79[1].B()
	if err != nil {
		return false, err
	}
	tmp81, err := this.Ac.Bits()
	if err != nil {
		return false, err
	}
	tmp82, err := tmp81[0].B()
	if err != nil {
		return false, err
	}
	tmp83, err := this.Ac.Bits()
	if err != nil {
		return false, err
	}
	tmp84, err := tmp83[2].B()
	if err != nil {
		return false, err
	}
	this.decrementAvailable = bool( (( ((tmp80) || (!(tmp82))) ) && (!(tmp84))) )
	return this.decrementAvailable, nil
}
func (this *MifareClassic_Trailer_AccessConditions_DataAc) IncrementAvailable() (v bool, err error) {
	if (this._f_incrementAvailable) {
		return this.incrementAvailable, nil
	}
	this._f_incrementAvailable = true
	tmp85, err := this.Ac.Bits()
	if err != nil {
		return false, err
	}
	tmp86, err := tmp85[0].B()
	if err != nil {
		return false, err
	}
	tmp87, err := this.ReadKeyARequired()
	if err != nil {
		return false, err
	}
	tmp88, err := this.ReadKeyBRequired()
	if err != nil {
		return false, err
	}
	tmp89, err := this.Ac.Bits()
	if err != nil {
		return false, err
	}
	tmp90, err := tmp89[0].B()
	if err != nil {
		return false, err
	}
	tmp91, err := this.ReadKeyARequired()
	if err != nil {
		return false, err
	}
	tmp92, err := this.ReadKeyBRequired()
	if err != nil {
		return false, err
	}
	this.incrementAvailable = bool( (( ((!(tmp86)) && (!(tmp87)) && (!(tmp88))) ) || ( ((!(tmp90)) && (tmp91) && (tmp92)) )) )
	return this.incrementAvailable, nil
}
func (this *MifareClassic_Trailer_AccessConditions_DataAc) ReadKeyARequired() (v bool, err error) {
	if (this._f_readKeyARequired) {
		return this.readKeyARequired, nil
	}
	this._f_readKeyARequired = true
	tmp93, err := this.Ac.Val()
	if err != nil {
		return false, err
	}
	this.readKeyARequired = bool(tmp93 <= 4)
	return this.readKeyARequired, nil
}
func (this *MifareClassic_Trailer_AccessConditions_DataAc) ReadKeyBRequired() (v bool, err error) {
	if (this._f_readKeyBRequired) {
		return this.readKeyBRequired, nil
	}
	this._f_readKeyBRequired = true
	tmp94, err := this.Ac.Val()
	if err != nil {
		return false, err
	}
	this.readKeyBRequired = bool(tmp94 <= 6)
	return this.readKeyBRequired, nil
}
func (this *MifareClassic_Trailer_AccessConditions_DataAc) WriteKeyARequired() (v bool, err error) {
	if (this._f_writeKeyARequired) {
		return this.writeKeyARequired, nil
	}
	this._f_writeKeyARequired = true
	tmp95, err := this.Ac.Val()
	if err != nil {
		return false, err
	}
	this.writeKeyARequired = bool(tmp95 == 0)
	return this.writeKeyARequired, nil
}
func (this *MifareClassic_Trailer_AccessConditions_DataAc) WriteKeyBRequired() (v bool, err error) {
	if (this._f_writeKeyBRequired) {
		return this.writeKeyBRequired, nil
	}
	this._f_writeKeyBRequired = true
	tmp96, err := this.ReadKeyARequired()
	if err != nil {
		return false, err
	}
	tmp97, err := this.ReadKeyBRequired()
	if err != nil {
		return false, err
	}
	tmp98, err := this.Ac.Bits()
	if err != nil {
		return false, err
	}
	tmp99, err := tmp98[0].B()
	if err != nil {
		return false, err
	}
	this.writeKeyBRequired = bool( (( ((!(tmp96)) || (tmp97)) ) && (!(tmp99))) )
	return this.writeKeyBRequired, nil
}
type MifareClassic_Trailer_AccessConditions_TrailerAc struct {
	Ac *MifareClassic_Trailer_AccessConditions_Ac
	_io *kaitai.Stream
	_root *MifareClassic
	_parent *MifareClassic_Trailer_AccessConditions
	_f_canReadKeyB bool
	canReadKeyB bool
	_f_canWriteAccessBits bool
	canWriteAccessBits bool
	_f_canWriteKeys bool
	canWriteKeys bool
	_f_keyBControlsWrite bool
	keyBControlsWrite bool
}
func NewMifareClassic_Trailer_AccessConditions_TrailerAc(ac *MifareClassic_Trailer_AccessConditions_Ac) *MifareClassic_Trailer_AccessConditions_TrailerAc {
	return &MifareClassic_Trailer_AccessConditions_TrailerAc{
		Ac: ac,
	}
}

func (this MifareClassic_Trailer_AccessConditions_TrailerAc) IO_() *kaitai.Stream {
	return this._io
}

func (this *MifareClassic_Trailer_AccessConditions_TrailerAc) Read(io *kaitai.Stream, parent *MifareClassic_Trailer_AccessConditions, root *MifareClassic) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	return err
}

/**
 * key A is required
 */
func (this *MifareClassic_Trailer_AccessConditions_TrailerAc) CanReadKeyB() (v bool, err error) {
	if (this._f_canReadKeyB) {
		return this.canReadKeyB, nil
	}
	this._f_canReadKeyB = true
	tmp100, err := this.Ac.InvShiftVal()
	if err != nil {
		return false, err
	}
	this.canReadKeyB = bool(tmp100 <= 2)
	return this.canReadKeyB, nil
}
func (this *MifareClassic_Trailer_AccessConditions_TrailerAc) CanWriteAccessBits() (v bool, err error) {
	if (this._f_canWriteAccessBits) {
		return this.canWriteAccessBits, nil
	}
	this._f_canWriteAccessBits = true
	tmp101, err := this.Ac.Bits()
	if err != nil {
		return false, err
	}
	tmp102, err := tmp101[2].B()
	if err != nil {
		return false, err
	}
	this.canWriteAccessBits = bool(tmp102)
	return this.canWriteAccessBits, nil
}
func (this *MifareClassic_Trailer_AccessConditions_TrailerAc) CanWriteKeys() (v bool, err error) {
	if (this._f_canWriteKeys) {
		return this.canWriteKeys, nil
	}
	this._f_canWriteKeys = true
	tmp104, err := this.Ac.InvShiftVal()
	if err != nil {
		return false, err
	}
	tmp103 := (tmp104 + 1) % 3
	if tmp103 < 0 {
		tmp103 += 3
	}
	tmp105, err := this.Ac.InvShiftVal()
	if err != nil {
		return false, err
	}
	this.canWriteKeys = bool( ((tmp103 != 0) && (tmp105 < 6)) )
	return this.canWriteKeys, nil
}
func (this *MifareClassic_Trailer_AccessConditions_TrailerAc) KeyBControlsWrite() (v bool, err error) {
	if (this._f_keyBControlsWrite) {
		return this.keyBControlsWrite, nil
	}
	this._f_keyBControlsWrite = true
	tmp106, err := this.CanReadKeyB()
	if err != nil {
		return false, err
	}
	this.keyBControlsWrite = bool(!(tmp106))
	return this.keyBControlsWrite, nil
}
type MifareClassic_Trailer_AccessConditions_ValidChunk struct {
	InvChunk uint8
	Chunk uint8
	_io *kaitai.Stream
	_root *MifareClassic
	_parent *MifareClassic_Trailer_AccessConditions
	_f_valid bool
	valid bool
}
func NewMifareClassic_Trailer_AccessConditions_ValidChunk(invChunk uint8, chunk uint8) *MifareClassic_Trailer_AccessConditions_ValidChunk {
	return &MifareClassic_Trailer_AccessConditions_ValidChunk{
		InvChunk: invChunk,
		Chunk: chunk,
	}
}

func (this MifareClassic_Trailer_AccessConditions_ValidChunk) IO_() *kaitai.Stream {
	return this._io
}

func (this *MifareClassic_Trailer_AccessConditions_ValidChunk) Read(io *kaitai.Stream, parent *MifareClassic_Trailer_AccessConditions, root *MifareClassic) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	return err
}
func (this *MifareClassic_Trailer_AccessConditions_ValidChunk) Valid() (v bool, err error) {
	if (this._f_valid) {
		return this.valid, nil
	}
	this._f_valid = true
	this.valid = bool(this.InvChunk ^ this.Chunk == 15)
	return this.valid, nil
}