Mifare Classic RFID tag dump: C# parsing library

You can get a dump for testing by the 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.

Usage

Runtime library

All parsing code for C# generated by Kaitai Struct depends on the C# runtime library. You have to install it before you can parse data.

The C# runtime library is available in the NuGet Gallery. Installation instructions can also be found there.

Code

Parse a local file and get structure in memory:

var data = MifareClassic.FromFile("path/to/local/file.mfd");

Or parse structure from a byte array:

byte[] someArray = new byte[] { ... };
var data = new MifareClassic(new KaitaiStream(someArray));

After that, one can get various attributes from the structure by accessing properties like:

data.Sectors // => get sectors

C# source code to parse Mifare Classic RFID tag dump

MifareClassic.cs

// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

using System.Collections.Generic;

namespace Kaitai
{

    /// <summary>
    /// You can get a dump for testing by the link: https://github.com/zhovner/mfdread/raw/master/dump.mfd
    /// </summary>
    /// <remarks>
    /// Reference: <a href="https://github.com/nfc-tools/libnfc
    /// https://www.nxp.com/docs/en/data-sheet/MF1S70YYX_V1.pdf
    /// ">Source</a>
    /// </remarks>
    public partial class MifareClassic : KaitaiStruct
    {
        public static MifareClassic FromFile(string fileName)
        {
            return new MifareClassic(new KaitaiStream(fileName));
        }

        public MifareClassic(KaitaiStream p__io, KaitaiStruct p__parent = null, MifareClassic p__root = null) : base(p__io)
        {
            m_parent = p__parent;
            m_root = p__root ?? this;
            _read();
        }
        private void _read()
        {
            __raw_sectors = new List<byte[]>();
            _sectors = new List<Sector>();
            {
                var i = 0;
                while (!m_io.IsEof) {
                    __raw_sectors.Add(m_io.ReadBytes((((i >= 32 ? 4 : 1) * 4) * 16)));
                    var io___raw_sectors = new KaitaiStream(__raw_sectors[__raw_sectors.Count - 1]);
                    _sectors.Add(new Sector(i == 0, io___raw_sectors, this, m_root));
                    i++;
                }
            }
        }
        public partial class Key : KaitaiStruct
        {
            public static Key FromFile(string fileName)
            {
                return new Key(new KaitaiStream(fileName));
            }

            public Key(KaitaiStream p__io, MifareClassic.Trailer p__parent = null, MifareClassic p__root = null) : base(p__io)
            {
                m_parent = p__parent;
                m_root = p__root;
                _read();
            }
            private void _read()
            {
                _key = m_io.ReadBytes(6);
            }
            private byte[] _key;
            private MifareClassic m_root;
            private MifareClassic.Trailer m_parent;
            public byte[] Key { get { return _key; } }
            public MifareClassic M_Root { get { return m_root; } }
            public MifareClassic.Trailer M_Parent { get { return m_parent; } }
        }
        public partial class Sector : KaitaiStruct
        {
            public Sector(bool p_hasManufacturer, KaitaiStream p__io, MifareClassic p__parent = null, MifareClassic p__root = null) : base(p__io)
            {
                m_parent = p__parent;
                m_root = p__root;
                _hasManufacturer = p_hasManufacturer;
                f_blockSize = false;
                f_data = false;
                f_blocks = false;
                f_values = false;
                _read();
            }
            private void _read()
            {
                if (HasManufacturer) {
                    _manufacturer = new Manufacturer(m_io, this, m_root);
                }
                __raw_dataFiller = m_io.ReadBytes(((M_Io.Size - M_Io.Pos) - 16));
                var io___raw_dataFiller = new KaitaiStream(__raw_dataFiller);
                _dataFiller = new Filler(io___raw_dataFiller, this, m_root);
                _trailer = new Trailer(m_io, this, m_root);
            }
            public partial class Values : KaitaiStruct
            {
                public static Values FromFile(string fileName)
                {
                    return new Values(new KaitaiStream(fileName));
                }

                public Values(KaitaiStream p__io, MifareClassic.Sector p__parent = null, MifareClassic p__root = null) : base(p__io)
                {
                    m_parent = p__parent;
                    m_root = p__root;
                    _read();
                }
                private void _read()
                {
                    _values = new List<ValueBlock>();
                    {
                        var i = 0;
                        while (!m_io.IsEof) {
                            _values.Add(new ValueBlock(m_io, this, m_root));
                            i++;
                        }
                    }
                }
                public partial class ValueBlock : KaitaiStruct
                {
                    public static ValueBlock FromFile(string fileName)
                    {
                        return new ValueBlock(new KaitaiStream(fileName));
                    }

                    public ValueBlock(KaitaiStream p__io, MifareClassic.Sector.Values p__parent = null, MifareClassic p__root = null) : base(p__io)
                    {
                        m_parent = p__parent;
                        m_root = p__root;
                        f_addr = false;
                        f_addrValid = false;
                        f_valid = false;
                        f_valueValid = false;
                        f_value = false;
                        _read();
                    }
                    private void _read()
                    {
                        _valuez = new List<uint>((int) (3));
                        for (var i = 0; i < 3; i++)
                        {
                            _valuez.Add(m_io.ReadU4le());
                        }
                        _addrz = new List<byte>((int) (4));
                        for (var i = 0; i < 4; i++)
                        {
                            _addrz.Add(m_io.ReadU1());
                        }
                    }
                    private bool f_addr;
                    private byte? _addr;
                    public byte? Addr
                    {
                        get
                        {
                            if (f_addr)
                                return _addr;
                            if (Valid) {
                                _addr = (byte) (Addrz[0]);
                            }
                            f_addr = true;
                            return _addr;
                        }
                    }
                    private bool f_addrValid;
                    private bool _addrValid;
                    public bool AddrValid
                    {
                        get
                        {
                            if (f_addrValid)
                                return _addrValid;
                            _addrValid = (bool) ( ((Addrz[0] == ~(Addrz[1])) && (Addrz[0] == Addrz[2]) && (Addrz[1] == Addrz[3])) );
                            f_addrValid = true;
                            return _addrValid;
                        }
                    }
                    private bool f_valid;
                    private bool _valid;
                    public bool Valid
                    {
                        get
                        {
                            if (f_valid)
                                return _valid;
                            _valid = (bool) ( ((ValueValid) && (AddrValid)) );
                            f_valid = true;
                            return _valid;
                        }
                    }
                    private bool f_valueValid;
                    private bool _valueValid;
                    public bool ValueValid
                    {
                        get
                        {
                            if (f_valueValid)
                                return _valueValid;
                            _valueValid = (bool) ( ((Valuez[0] == ~(Valuez[1])) && (Valuez[0] == Valuez[2])) );
                            f_valueValid = true;
                            return _valueValid;
                        }
                    }
                    private bool f_value;
                    private uint? _value;
                    public uint? Value
                    {
                        get
                        {
                            if (f_value)
                                return _value;
                            if (Valid) {
                                _value = (uint) (Valuez[0]);
                            }
                            f_value = true;
                            return _value;
                        }
                    }
                    private List<uint> _valuez;
                    private List<byte> _addrz;
                    private MifareClassic m_root;
                    private MifareClassic.Sector.Values m_parent;
                    public List<uint> Valuez { get { return _valuez; } }
                    public List<byte> Addrz { get { return _addrz; } }
                    public MifareClassic M_Root { get { return m_root; } }
                    public MifareClassic.Sector.Values M_Parent { get { return m_parent; } }
                }
                private List<ValueBlock> _values;
                private MifareClassic m_root;
                private MifareClassic.Sector m_parent;
                public List<ValueBlock> Values { get { return _values; } }
                public MifareClassic M_Root { get { return m_root; } }
                public MifareClassic.Sector M_Parent { get { return m_parent; } }
            }

            /// <summary>
            /// only to create _io
            /// </summary>
            public partial class Filler : KaitaiStruct
            {
                public static Filler FromFile(string fileName)
                {
                    return new Filler(new KaitaiStream(fileName));
                }

                public Filler(KaitaiStream p__io, MifareClassic.Sector p__parent = null, MifareClassic p__root = null) : base(p__io)
                {
                    m_parent = p__parent;
                    m_root = p__root;
                    _read();
                }
                private void _read()
                {
                    _data = m_io.ReadBytes(M_Io.Size);
                }
                private byte[] _data;
                private MifareClassic m_root;
                private MifareClassic.Sector m_parent;
                public byte[] Data { get { return _data; } }
                public MifareClassic M_Root { get { return m_root; } }
                public MifareClassic.Sector M_Parent { get { return m_parent; } }
            }
            private bool f_blockSize;
            private sbyte _blockSize;
            public sbyte BlockSize
            {
                get
                {
                    if (f_blockSize)
                        return _blockSize;
                    _blockSize = (sbyte) (16);
                    f_blockSize = true;
                    return _blockSize;
                }
            }
            private bool f_data;
            private byte[] _data;
            public byte[] Data
            {
                get
                {
                    if (f_data)
                        return _data;
                    _data = (byte[]) (DataFiller.Data);
                    f_data = true;
                    return _data;
                }
            }
            private bool f_blocks;
            private List<byte[]> _blocks;
            public List<byte[]> Blocks
            {
                get
                {
                    if (f_blocks)
                        return _blocks;
                    KaitaiStream io = DataFiller.M_Io;
                    long _pos = io.Pos;
                    io.Seek(0);
                    _blocks = new List<byte[]>();
                    {
                        var i = 0;
                        while (!io.IsEof) {
                            _blocks.Add(io.ReadBytes(BlockSize));
                            i++;
                        }
                    }
                    io.Seek(_pos);
                    f_blocks = true;
                    return _blocks;
                }
            }
            private bool f_values;
            private Values _values;
            public Values Values
            {
                get
                {
                    if (f_values)
                        return _values;
                    KaitaiStream io = DataFiller.M_Io;
                    long _pos = io.Pos;
                    io.Seek(0);
                    _values = new Values(io, this, m_root);
                    io.Seek(_pos);
                    f_values = true;
                    return _values;
                }
            }
            private Manufacturer _manufacturer;
            private Filler _dataFiller;
            private Trailer _trailer;
            private bool _hasManufacturer;
            private MifareClassic m_root;
            private MifareClassic m_parent;
            private byte[] __raw_dataFiller;
            public Manufacturer Manufacturer { get { return _manufacturer; } }
            public Filler DataFiller { get { return _dataFiller; } }
            public Trailer Trailer { get { return _trailer; } }
            public bool HasManufacturer { get { return _hasManufacturer; } }
            public MifareClassic M_Root { get { return m_root; } }
            public MifareClassic M_Parent { get { return m_parent; } }
            public byte[] M_RawDataFiller { get { return __raw_dataFiller; } }
        }
        public partial class Manufacturer : KaitaiStruct
        {
            public static Manufacturer FromFile(string fileName)
            {
                return new Manufacturer(new KaitaiStream(fileName));
            }

            public Manufacturer(KaitaiStream p__io, MifareClassic.Sector p__parent = null, MifareClassic p__root = null) : base(p__io)
            {
                m_parent = p__parent;
                m_root = p__root;
                _read();
            }
            private void _read()
            {
                _nuid = m_io.ReadU4le();
                _bcc = m_io.ReadU1();
                _sak = m_io.ReadU1();
                _atqa = m_io.ReadU2le();
                _manufacturer = m_io.ReadBytes(8);
            }
            private uint _nuid;
            private byte _bcc;
            private byte _sak;
            private ushort _atqa;
            private byte[] _manufacturer;
            private MifareClassic m_root;
            private MifareClassic.Sector m_parent;

            /// <summary>
            /// beware for 7bytes UID it goes over next fields
            /// </summary>
            public uint Nuid { get { return _nuid; } }
            public byte Bcc { get { return _bcc; } }
            public byte Sak { get { return _sak; } }
            public ushort Atqa { get { return _atqa; } }

            /// <summary>
            /// may contain manufacture date as BCD
            /// </summary>
            public byte[] Manufacturer { get { return _manufacturer; } }
            public MifareClassic M_Root { get { return m_root; } }
            public MifareClassic.Sector M_Parent { get { return m_parent; } }
        }
        public partial class Trailer : KaitaiStruct
        {
            public static Trailer FromFile(string fileName)
            {
                return new Trailer(new KaitaiStream(fileName));
            }

            public Trailer(KaitaiStream p__io, MifareClassic.Sector p__parent = null, MifareClassic p__root = null) : base(p__io)
            {
                m_parent = p__parent;
                m_root = p__root;
                f_acBits = false;
                f_acsInSector = false;
                f_acCountOfChunks = false;
                _read();
            }
            private void _read()
            {
                _keyA = new Key(m_io, this, m_root);
                __raw_accessBits = m_io.ReadBytes(3);
                var io___raw_accessBits = new KaitaiStream(__raw_accessBits);
                _accessBits = new AccessConditions(io___raw_accessBits, this, m_root);
                _userByte = m_io.ReadU1();
                _keyB = new Key(m_io, this, m_root);
            }
            public partial class AccessConditions : KaitaiStruct
            {
                public static AccessConditions FromFile(string fileName)
                {
                    return new AccessConditions(new KaitaiStream(fileName));
                }

                public AccessConditions(KaitaiStream p__io, MifareClassic.Trailer p__parent = null, MifareClassic p__root = null) : base(p__io)
                {
                    m_parent = p__parent;
                    m_root = p__root;
                    f_dataAcs = false;
                    f_remaps = false;
                    f_acsRaw = false;
                    f_trailerAc = false;
                    f_chunks = false;
                    _read();
                }
                private void _read()
                {
                    _rawChunks = new List<ulong>((int) (M_Parent.AcCountOfChunks));
                    for (var i = 0; i < M_Parent.AcCountOfChunks; i++)
                    {
                        _rawChunks.Add(m_io.ReadBitsIntBe(4));
                    }
                }
                public partial class TrailerAc : KaitaiStruct
                {
                    public TrailerAc(Ac p_ac, KaitaiStream p__io, MifareClassic.Trailer.AccessConditions p__parent = null, MifareClassic p__root = null) : base(p__io)
                    {
                        m_parent = p__parent;
                        m_root = p__root;
                        _ac = p_ac;
                        f_canReadKeyB = false;
                        f_canWriteKeys = false;
                        f_canWriteAccessBits = false;
                        f_keyBControlsWrite = false;
                        _read();
                    }
                    private void _read()
                    {
                    }
                    private bool f_canReadKeyB;
                    private bool _canReadKeyB;

                    /// <summary>
                    /// key A is required
                    /// </summary>
                    public bool CanReadKeyB
                    {
                        get
                        {
                            if (f_canReadKeyB)
                                return _canReadKeyB;
                            _canReadKeyB = (bool) (Ac.InvShiftVal <= 2);
                            f_canReadKeyB = true;
                            return _canReadKeyB;
                        }
                    }
                    private bool f_canWriteKeys;
                    private bool _canWriteKeys;
                    public bool CanWriteKeys
                    {
                        get
                        {
                            if (f_canWriteKeys)
                                return _canWriteKeys;
                            _canWriteKeys = (bool) ( ((KaitaiStream.Mod((Ac.InvShiftVal + 1), 3) != 0) && (Ac.InvShiftVal < 6)) );
                            f_canWriteKeys = true;
                            return _canWriteKeys;
                        }
                    }
                    private bool f_canWriteAccessBits;
                    private bool _canWriteAccessBits;
                    public bool CanWriteAccessBits
                    {
                        get
                        {
                            if (f_canWriteAccessBits)
                                return _canWriteAccessBits;
                            _canWriteAccessBits = (bool) (Ac.Bits[2].B);
                            f_canWriteAccessBits = true;
                            return _canWriteAccessBits;
                        }
                    }
                    private bool f_keyBControlsWrite;
                    private bool _keyBControlsWrite;
                    public bool KeyBControlsWrite
                    {
                        get
                        {
                            if (f_keyBControlsWrite)
                                return _keyBControlsWrite;
                            _keyBControlsWrite = (bool) (!(CanReadKeyB));
                            f_keyBControlsWrite = true;
                            return _keyBControlsWrite;
                        }
                    }
                    private Ac _ac;
                    private MifareClassic m_root;
                    private MifareClassic.Trailer.AccessConditions m_parent;
                    public Ac Ac { get { return _ac; } }
                    public MifareClassic M_Root { get { return m_root; } }
                    public MifareClassic.Trailer.AccessConditions M_Parent { get { return m_parent; } }
                }
                public partial class ChunkBitRemap : KaitaiStruct
                {
                    public ChunkBitRemap(byte p_bitNo, KaitaiStream p__io, MifareClassic.Trailer.AccessConditions p__parent = null, MifareClassic p__root = null) : base(p__io)
                    {
                        m_parent = p__parent;
                        m_root = p__root;
                        _bitNo = p_bitNo;
                        f_shiftValue = false;
                        f_chunkNo = false;
                        f_invChunkNo = false;
                        _read();
                    }
                    private void _read()
                    {
                    }
                    private bool f_shiftValue;
                    private int _shiftValue;
                    public int ShiftValue
                    {
                        get
                        {
                            if (f_shiftValue)
                                return _shiftValue;
                            _shiftValue = (int) ((BitNo == 1 ? -1 : 1));
                            f_shiftValue = true;
                            return _shiftValue;
                        }
                    }
                    private bool f_chunkNo;
                    private int _chunkNo;
                    public int ChunkNo
                    {
                        get
                        {
                            if (f_chunkNo)
                                return _chunkNo;
                            _chunkNo = (int) (KaitaiStream.Mod(((InvChunkNo + ShiftValue) + M_Parent.M_Parent.AcCountOfChunks), M_Parent.M_Parent.AcCountOfChunks));
                            f_chunkNo = true;
                            return _chunkNo;
                        }
                    }
                    private bool f_invChunkNo;
                    private int _invChunkNo;
                    public int InvChunkNo
                    {
                        get
                        {
                            if (f_invChunkNo)
                                return _invChunkNo;
                            _invChunkNo = (int) ((BitNo + ShiftValue));
                            f_invChunkNo = true;
                            return _invChunkNo;
                        }
                    }
                    private byte _bitNo;
                    private MifareClassic m_root;
                    private MifareClassic.Trailer.AccessConditions m_parent;
                    public byte BitNo { get { return _bitNo; } }
                    public MifareClassic M_Root { get { return m_root; } }
                    public MifareClassic.Trailer.AccessConditions M_Parent { get { return m_parent; } }
                }
                public partial class DataAc : KaitaiStruct
                {
                    public DataAc(Ac p_ac, KaitaiStream p__io, MifareClassic.Trailer.AccessConditions p__parent = null, MifareClassic p__root = null) : base(p__io)
                    {
                        m_parent = p__parent;
                        m_root = p__root;
                        _ac = p_ac;
                        f_readKeyARequired = false;
                        f_writeKeyBRequired = false;
                        f_writeKeyARequired = false;
                        f_readKeyBRequired = false;
                        f_decrementAvailable = false;
                        f_incrementAvailable = false;
                        _read();
                    }
                    private void _read()
                    {
                    }
                    private bool f_readKeyARequired;
                    private bool _readKeyARequired;
                    public bool ReadKeyARequired
                    {
                        get
                        {
                            if (f_readKeyARequired)
                                return _readKeyARequired;
                            _readKeyARequired = (bool) (Ac.Val <= 4);
                            f_readKeyARequired = true;
                            return _readKeyARequired;
                        }
                    }
                    private bool f_writeKeyBRequired;
                    private bool _writeKeyBRequired;
                    public bool WriteKeyBRequired
                    {
                        get
                        {
                            if (f_writeKeyBRequired)
                                return _writeKeyBRequired;
                            _writeKeyBRequired = (bool) ( (( ((!(ReadKeyARequired)) || (ReadKeyBRequired)) ) && (!(Ac.Bits[0].B))) );
                            f_writeKeyBRequired = true;
                            return _writeKeyBRequired;
                        }
                    }
                    private bool f_writeKeyARequired;
                    private bool _writeKeyARequired;
                    public bool WriteKeyARequired
                    {
                        get
                        {
                            if (f_writeKeyARequired)
                                return _writeKeyARequired;
                            _writeKeyARequired = (bool) (Ac.Val == 0);
                            f_writeKeyARequired = true;
                            return _writeKeyARequired;
                        }
                    }
                    private bool f_readKeyBRequired;
                    private bool _readKeyBRequired;
                    public bool ReadKeyBRequired
                    {
                        get
                        {
                            if (f_readKeyBRequired)
                                return _readKeyBRequired;
                            _readKeyBRequired = (bool) (Ac.Val <= 6);
                            f_readKeyBRequired = true;
                            return _readKeyBRequired;
                        }
                    }
                    private bool f_decrementAvailable;
                    private bool _decrementAvailable;
                    public bool DecrementAvailable
                    {
                        get
                        {
                            if (f_decrementAvailable)
                                return _decrementAvailable;
                            _decrementAvailable = (bool) ( (( ((Ac.Bits[1].B) || (!(Ac.Bits[0].B))) ) && (!(Ac.Bits[2].B))) );
                            f_decrementAvailable = true;
                            return _decrementAvailable;
                        }
                    }
                    private bool f_incrementAvailable;
                    private bool _incrementAvailable;
                    public bool IncrementAvailable
                    {
                        get
                        {
                            if (f_incrementAvailable)
                                return _incrementAvailable;
                            _incrementAvailable = (bool) ( (( ((!(Ac.Bits[0].B)) && (!(ReadKeyARequired)) && (!(ReadKeyBRequired))) ) || ( ((!(Ac.Bits[0].B)) && (ReadKeyARequired) && (ReadKeyBRequired)) )) );
                            f_incrementAvailable = true;
                            return _incrementAvailable;
                        }
                    }
                    private Ac _ac;
                    private MifareClassic m_root;
                    private MifareClassic.Trailer.AccessConditions m_parent;
                    public Ac Ac { get { return _ac; } }
                    public MifareClassic M_Root { get { return m_root; } }
                    public MifareClassic.Trailer.AccessConditions M_Parent { get { return m_parent; } }
                }
                public partial class Ac : KaitaiStruct
                {
                    public Ac(byte p_index, KaitaiStream p__io, MifareClassic.Trailer.AccessConditions p__parent = null, MifareClassic p__root = null) : base(p__io)
                    {
                        m_parent = p__parent;
                        m_root = p__root;
                        _index = p_index;
                        f_bits = false;
                        f_val = false;
                        f_invShiftVal = false;
                        _read();
                    }
                    private void _read()
                    {
                    }
                    public partial class AcBit : KaitaiStruct
                    {
                        public AcBit(byte p_i, byte p_chunk, KaitaiStream p__io, MifareClassic.Trailer.AccessConditions.Ac p__parent = null, MifareClassic p__root = null) : base(p__io)
                        {
                            m_parent = p__parent;
                            m_root = p__root;
                            _i = p_i;
                            _chunk = p_chunk;
                            f_n = false;
                            f_b = false;
                            _read();
                        }
                        private void _read()
                        {
                        }
                        private bool f_n;
                        private int _n;
                        public int N
                        {
                            get
                            {
                                if (f_n)
                                    return _n;
                                _n = (int) (((Chunk >> I) & 1));
                                f_n = true;
                                return _n;
                            }
                        }
                        private bool f_b;
                        private bool _b;
                        public bool B
                        {
                            get
                            {
                                if (f_b)
                                    return _b;
                                _b = (bool) (N == 1);
                                f_b = true;
                                return _b;
                            }
                        }
                        private byte _i;
                        private byte _chunk;
                        private MifareClassic m_root;
                        private MifareClassic.Trailer.AccessConditions.Ac m_parent;
                        public byte I { get { return _i; } }
                        public byte Chunk { get { return _chunk; } }
                        public MifareClassic M_Root { get { return m_root; } }
                        public MifareClassic.Trailer.AccessConditions.Ac M_Parent { get { return m_parent; } }
                    }
                    private bool f_bits;
                    private List<AcBit> _bits;
                    public List<AcBit> Bits
                    {
                        get
                        {
                            if (f_bits)
                                return _bits;
                            long _pos = m_io.Pos;
                            m_io.Seek(0);
                            _bits = new List<AcBit>((int) (M_Parent.M_Parent.AcBits));
                            for (var i = 0; i < M_Parent.M_Parent.AcBits; i++)
                            {
                                _bits.Add(new AcBit(Index, M_Parent.Chunks[i].Chunk, m_io, this, m_root));
                            }
                            m_io.Seek(_pos);
                            f_bits = true;
                            return _bits;
                        }
                    }
                    private bool f_val;
                    private int _val;

                    /// <summary>
                    /// c3 c2 c1
                    /// </summary>
                    public int Val
                    {
                        get
                        {
                            if (f_val)
                                return _val;
                            _val = (int) ((((Bits[2].N << 2) | (Bits[1].N << 1)) | Bits[0].N));
                            f_val = true;
                            return _val;
                        }
                    }
                    private bool f_invShiftVal;
                    private int _invShiftVal;
                    public int InvShiftVal
                    {
                        get
                        {
                            if (f_invShiftVal)
                                return _invShiftVal;
                            _invShiftVal = (int) ((((Bits[0].N << 2) | (Bits[1].N << 1)) | Bits[2].N));
                            f_invShiftVal = true;
                            return _invShiftVal;
                        }
                    }
                    private byte _index;
                    private MifareClassic m_root;
                    private MifareClassic.Trailer.AccessConditions m_parent;
                    public byte Index { get { return _index; } }
                    public MifareClassic M_Root { get { return m_root; } }
                    public MifareClassic.Trailer.AccessConditions M_Parent { get { return m_parent; } }
                }
                public partial class ValidChunk : KaitaiStruct
                {
                    public ValidChunk(byte p_invChunk, byte p_chunk, KaitaiStream p__io, MifareClassic.Trailer.AccessConditions p__parent = null, MifareClassic p__root = null) : base(p__io)
                    {
                        m_parent = p__parent;
                        m_root = p__root;
                        _invChunk = p_invChunk;
                        _chunk = p_chunk;
                        f_valid = false;
                        _read();
                    }
                    private void _read()
                    {
                    }
                    private bool f_valid;
                    private bool _valid;
                    public bool Valid
                    {
                        get
                        {
                            if (f_valid)
                                return _valid;
                            _valid = (bool) ((InvChunk ^ Chunk) == 15);
                            f_valid = true;
                            return _valid;
                        }
                    }
                    private byte _invChunk;
                    private byte _chunk;
                    private MifareClassic m_root;
                    private MifareClassic.Trailer.AccessConditions m_parent;
                    public byte InvChunk { get { return _invChunk; } }

                    /// <summary>
                    /// c3 c2 c1 c0
                    /// </summary>
                    public byte Chunk { get { return _chunk; } }
                    public MifareClassic M_Root { get { return m_root; } }
                    public MifareClassic.Trailer.AccessConditions M_Parent { get { return m_parent; } }
                }
                private bool f_dataAcs;
                private List<DataAc> _dataAcs;
                public List<DataAc> DataAcs
                {
                    get
                    {
                        if (f_dataAcs)
                            return _dataAcs;
                        long _pos = m_io.Pos;
                        m_io.Seek(0);
                        _dataAcs = new List<DataAc>((int) ((M_Parent.AcsInSector - 1)));
                        for (var i = 0; i < (M_Parent.AcsInSector - 1); i++)
                        {
                            _dataAcs.Add(new DataAc(AcsRaw[i], m_io, this, m_root));
                        }
                        m_io.Seek(_pos);
                        f_dataAcs = true;
                        return _dataAcs;
                    }
                }
                private bool f_remaps;
                private List<ChunkBitRemap> _remaps;
                public List<ChunkBitRemap> Remaps
                {
                    get
                    {
                        if (f_remaps)
                            return _remaps;
                        long _pos = m_io.Pos;
                        m_io.Seek(0);
                        _remaps = new List<ChunkBitRemap>((int) (M_Parent.AcBits));
                        for (var i = 0; i < M_Parent.AcBits; i++)
                        {
                            _remaps.Add(new ChunkBitRemap(i, m_io, this, m_root));
                        }
                        m_io.Seek(_pos);
                        f_remaps = true;
                        return _remaps;
                    }
                }
                private bool f_acsRaw;
                private List<Ac> _acsRaw;
                public List<Ac> AcsRaw
                {
                    get
                    {
                        if (f_acsRaw)
                            return _acsRaw;
                        long _pos = m_io.Pos;
                        m_io.Seek(0);
                        _acsRaw = new List<Ac>((int) (M_Parent.AcsInSector));
                        for (var i = 0; i < M_Parent.AcsInSector; i++)
                        {
                            _acsRaw.Add(new Ac(i, m_io, this, m_root));
                        }
                        m_io.Seek(_pos);
                        f_acsRaw = true;
                        return _acsRaw;
                    }
                }
                private bool f_trailerAc;
                private TrailerAc _trailerAc;
                public TrailerAc TrailerAc
                {
                    get
                    {
                        if (f_trailerAc)
                            return _trailerAc;
                        long _pos = m_io.Pos;
                        m_io.Seek(0);
                        _trailerAc = new TrailerAc(AcsRaw[(M_Parent.AcsInSector - 1)], m_io, this, m_root);
                        m_io.Seek(_pos);
                        f_trailerAc = true;
                        return _trailerAc;
                    }
                }
                private bool f_chunks;
                private List<ValidChunk> _chunks;
                public List<ValidChunk> Chunks
                {
                    get
                    {
                        if (f_chunks)
                            return _chunks;
                        long _pos = m_io.Pos;
                        m_io.Seek(0);
                        _chunks = new List<ValidChunk>((int) (M_Parent.AcBits));
                        for (var i = 0; i < M_Parent.AcBits; i++)
                        {
                            _chunks.Add(new ValidChunk(RawChunks[Remaps[i].InvChunkNo], RawChunks[Remaps[i].ChunkNo], m_io, this, m_root));
                        }
                        m_io.Seek(_pos);
                        f_chunks = true;
                        return _chunks;
                    }
                }
                private List<ulong> _rawChunks;
                private MifareClassic m_root;
                private MifareClassic.Trailer m_parent;
                public List<ulong> RawChunks { get { return _rawChunks; } }
                public MifareClassic M_Root { get { return m_root; } }
                public MifareClassic.Trailer M_Parent { get { return m_parent; } }
            }
            private bool f_acBits;
            private sbyte _acBits;
            public sbyte AcBits
            {
                get
                {
                    if (f_acBits)
                        return _acBits;
                    _acBits = (sbyte) (3);
                    f_acBits = true;
                    return _acBits;
                }
            }
            private bool f_acsInSector;
            private sbyte _acsInSector;
            public sbyte AcsInSector
            {
                get
                {
                    if (f_acsInSector)
                        return _acsInSector;
                    _acsInSector = (sbyte) (4);
                    f_acsInSector = true;
                    return _acsInSector;
                }
            }
            private bool f_acCountOfChunks;
            private int _acCountOfChunks;
            public int AcCountOfChunks
            {
                get
                {
                    if (f_acCountOfChunks)
                        return _acCountOfChunks;
                    _acCountOfChunks = (int) ((AcBits * 2));
                    f_acCountOfChunks = true;
                    return _acCountOfChunks;
                }
            }
            private Key _keyA;
            private AccessConditions _accessBits;
            private byte _userByte;
            private Key _keyB;
            private MifareClassic m_root;
            private MifareClassic.Sector m_parent;
            private byte[] __raw_accessBits;
            public Key KeyA { get { return _keyA; } }
            public AccessConditions AccessBits { get { return _accessBits; } }
            public byte UserByte { get { return _userByte; } }
            public Key KeyB { get { return _keyB; } }
            public MifareClassic M_Root { get { return m_root; } }
            public MifareClassic.Sector M_Parent { get { return m_parent; } }
            public byte[] M_RawAccessBits { get { return __raw_accessBits; } }
        }
        private List<Sector> _sectors;
        private MifareClassic m_root;
        private KaitaiStruct m_parent;
        private List<byte[]> __raw_sectors;
        public List<Sector> Sectors { get { return _sectors; } }
        public MifareClassic M_Root { get { return m_root; } }
        public KaitaiStruct M_Parent { get { return m_parent; } }
        public List<byte[]> M_RawSectors { get { return __raw_sectors; } }
    }
}