Example #1
0
        public byte[] WriteData(byte[] sessionKey, byte fileNo, byte dataIn)
        {
            //byte fileNo = 0x01;
            byte[] offset      = new byte[] { 0x00, 0x00, 0x00 }; //offset of 0
            byte[] length      = new byte[] { 0x00, 0x00, 0x01 }; //length of 1
            byte[] dataToWrite = new byte[] { dataIn };

            byte[] dataForCRC32Header = new byte[] { (byte)DesfireCommand.CommandType.WriteData, fileNo, offset[2], offset[1], offset[0], length[2], length[1], length[0] };
            byte[] dataForCRC32       = new byte[dataForCRC32Header.Length + dataToWrite.Length];
            Array.Copy(dataForCRC32Header, dataForCRC32, dataForCRC32Header.Length);
            Array.Copy(dataToWrite, 0, dataForCRC32, dataForCRC32Header.Length, dataToWrite.Length);

            uint   crc32       = Crc32.Compute(dataForCRC32);
            string dataPlusCRC = Formatting.ByteArrayToHexString(dataToWrite) + Formatting.ByteArrayToHexString(BitConverter.GetBytes(crc32));

            byte[] dataPlusCRCPadded = Formatting.HexStringToByteArray(dataPlusCRC);
            Formatting.PadToMultipleOf(ref dataPlusCRCPadded, 16);
            string initialIV = "00000000000000000000000000000000";

            byte[] dataPlusCRCResultPaddedEncrypted = AESCrypto.AESEncrypt(
                sessionKey,
                Formatting.HexStringToByteArray(initialIV),
                dataPlusCRCPadded);
            byte[] extractIV = new byte[16];
            Array.Copy(dataPlusCRCResultPaddedEncrypted, dataPlusCRCResultPaddedEncrypted.Length - 16, extractIV, 0, 16);

            byte[] cmdToSendHeader = new byte[] { fileNo, offset[2], offset[1], offset[0], length[2], length[1], length[0] };
            byte[] cmdToSend       = new byte[cmdToSendHeader.Length + dataPlusCRCResultPaddedEncrypted.Length];
            Array.Copy(cmdToSendHeader, cmdToSend, cmdToSendHeader.Length);
            Array.Copy(dataPlusCRCResultPaddedEncrypted, 0, cmdToSend, cmdToSendHeader.Length, dataPlusCRCResultPaddedEncrypted.Length);

            DesfireCommand desfireCommand = new DesfireCommand()
            {
                Command = (byte)DesfireCommand.CommandType.WriteData,
                Data    = cmdToSend
            };
            DesfireResponse desfireResFile = SendCommand(desfireCommand) as DesfireResponse;

            if (!desfireResFile.Succeeded)
            {
                throw new DesFireException("Error:" + desfireResFile.SW);
            }

            byte[] cmac = AESCMAC.CMAC(
                sessionKey,
                extractIV,
                new byte[] { desfireResFile.SW2 });

            byte[] updatedIV = cmac;

            byte[] data = ReadData(sessionKey, updatedIV, fileNo);

            if (data[0] != dataToWrite[0])
            {
                throw new DesFireException("Data read not the same as data written");
            }
            return(data);
        }
Example #2
0
        public byte[] ReadData(byte[] sessionKey, byte[] updatedIV, byte fileNo)
        {
            byte[] offset = new byte[] { 0x00, 0x00, 0x00 }; //offset of 0
            byte[] length = new byte[] { 0x00, 0x00, 0x01 }; //length of 1

            byte[] dataForCMAC = new byte[] { (byte)DesfireCommand.CommandType.ReadData, fileNo, offset[2], offset[1], offset[0], length[2], length[1], length[0] };
            byte[] cmac        = AESCMAC.CMAC(
                sessionKey,
                updatedIV,
                dataForCMAC);

            updatedIV = cmac;

            byte[]         cmdToSend      = new byte[] { fileNo, offset[2], offset[1], offset[0], length[2], length[1], length[0] };
            DesfireCommand desfireCommand = new DesfireCommand()
            {
                Command = (byte)DesfireCommand.CommandType.ReadData,
                Data    = cmdToSend
            };
            DesfireResponse desfireRes = SendCommand(desfireCommand) as DesfireResponse;

            if (!desfireRes.Succeeded)
            {
                throw new DesFireException("Error:" + desfireRes.SW);
            }

            byte[] dataBytes = AESCrypto.AESDecrypt(
                sessionKey,
                updatedIV,
                desfireRes.ResponseData);

            byte[] extractIV = new byte[16];
            Array.Copy(desfireRes.ResponseData, desfireRes.ResponseData.Length - 16, extractIV, 0, 16);

            int lengthofData = 0x01;

            byte[] data = new byte[lengthofData];
            Array.Copy(dataBytes, data, data.Length);
            byte[] crc = new byte[4];
            Array.Copy(dataBytes, data.Length, crc, 0, crc.Length); //crc is 4 bytes long
            byte[] dataPlusStatus = new byte[data.Length + 1];
            Array.Copy(data, dataPlusStatus, data.Length);
            Array.Copy(new byte[] { 0x00 }, 0, dataPlusStatus, data.Length, 1);
            uint crc32 = Crc32.Compute(dataPlusStatus);

            //compare crc32 to crc
            if (BitConverter.ToUInt32(crc, 0) != crc32)
            {
                throw new DesFireException("CRC32 error");
            }
            return(data);
        }
Example #3
0
        public static byte[] CMAC(byte[] key, byte[] iv, byte[] data)
        {
            // SubKey generation
            // step 1, AES-128 with key K is applied to an all-zero input block.
            byte[] L = AESCrypto.AESEncrypt(key, new byte[16], new byte[16]);

            // step 2, K1 is derived through the following operation:
            byte[] FirstSubkey = Rol(L); //If the most significant bit of L is equal to 0, K1 is the left-shift of L by 1 bit.
            if ((L[0] & 0x80) == 0x80)
            {
                FirstSubkey[15] ^= 0x87; // Otherwise, K1 is the exclusive-OR of const_Rb and the left-shift of L by 1 bit.
            }
            // step 3, K2 is derived through the following operation:
            byte[] SecondSubkey = Rol(FirstSubkey); // If the most significant bit of K1 is equal to 0, K2 is the left-shift of K1 by 1 bit.
            if ((FirstSubkey[0] & 0x80) == 0x80)
            {
                SecondSubkey[15] ^= 0x87; // Otherwise, K2 is the exclusive-OR of const_Rb and the left-shift of K1 by 1 bit.
            }
            // MAC computing
            if (((data.Length != 0) && (data.Length % 16 == 0)) == true)
            {
                // If the size of the input message block is equal to a positive multiple of the block size (namely, 128 bits),
                // the last block shall be exclusive-OR'ed with K1 before processing
                for (int j = 0; j < FirstSubkey.Length; j++)
                {
                    data[data.Length - 16 + j] ^= FirstSubkey[j];
                }
            }
            else
            {
                // Otherwise, the last block shall be padded with 10^i
                byte[] padding = new byte[16 - data.Length % 16];
                padding[0] = 0x80;

                data = data.Concat <byte>(padding.AsEnumerable()).ToArray();

                // and exclusive-OR'ed with K2
                for (int j = 0; j < SecondSubkey.Length; j++)
                {
                    data[data.Length - 16 + j] ^= SecondSubkey[j];
                }
            }

            // The result of the previous process will be the input of the last encryption.
            byte[] encResult = AESCrypto.AESEncrypt(key, iv, data);

            byte[] HashValue = new byte[16];
            Array.Copy(encResult, encResult.Length - HashValue.Length, HashValue, 0, HashValue.Length);

            return(HashValue);
        }
Example #4
0
        public byte[] AuthenticateAES()
        {
            string initialIV = "00000000000000000000000000000000";
            string key       = "00000000000000000000000000000000";

            DesfireCommand desfireCommand = new DesfireCommand()
            {
                Command = (byte)DesfireCommand.CommandType.AuthenticateAES,
                Data    = new byte[] { 0x00 } //1 byte key number
            };
            DesfireResponse desfireRes1 = SendCommand(desfireCommand) as DesfireResponse;

            if (!desfireRes1.SubsequentFrame) //additional frames expected
            {
                throw new DesFireException("Error:" + desfireRes1.SW);
            }

            byte[] rndBBytes = AESCrypto.AESDecrypt(
                Formatting.HexStringToByteArray(key),
                Formatting.HexStringToByteArray(initialIV),
                desfireRes1.ResponseData);

            byte[] rndBRotatedBytes    = Formatting.RotateRight(rndBBytes);
            string rndAGenerated       = "2347C1557F80707ABDFF86BF9D965CA7";
            string rndAPlusRndBRotated = rndAGenerated + Formatting.ByteArrayToHexString(rndBRotatedBytes);

            string ivNew = Formatting.ByteArrayToHexString(desfireRes1.ResponseData);

            byte[] rndAPlusRndBRotatedCipherBytes = AESCrypto.AESEncrypt(
                Formatting.HexStringToByteArray(key),
                Formatting.HexStringToByteArray(ivNew),
                Formatting.HexStringToByteArray(rndAPlusRndBRotated));

            desfireCommand = new DesfireCommand()
            {
                Command = (byte)DesfireCommand.CommandType.GetAdditionalFrame,
                Data    = rndAPlusRndBRotatedCipherBytes //32 byte enciphered RndA/RndB
            };
            byte[] extractIV = new byte[16];
            Array.Copy(rndAPlusRndBRotatedCipherBytes, rndAPlusRndBRotatedCipherBytes.Length - 16, extractIV, 0, 16);

            DesfireResponse desfireRes2 = SendCommand(desfireCommand) as DesfireResponse;

            if (!desfireRes2.Succeeded)
            {
                throw new DesFireException("Error:" + desfireRes2.SW);
            }

            byte[] rndARotatedBytes = AESCrypto.AESDecrypt(
                Formatting.HexStringToByteArray(key),
                extractIV,
                desfireRes2.ResponseData);

            byte[] rndABytes = Formatting.RotateLeft(rndARotatedBytes);
            if (rndAGenerated != Formatting.ByteArrayToHexString(rndABytes))
            {
                throw new DesFireException("rndA generated not same as rndA received");
            }

            string rndAString = Formatting.ByteArrayToHexString(rndABytes);
            string rndBString = Formatting.ByteArrayToHexString(rndBBytes);

            string sessionKey = rndAString.Substring(0, 8) + rndBString.Substring(0, 8) +
                                rndAString.Substring(24, 8) + rndBString.Substring(24, 8);

            return(Formatting.HexStringToByteArray(sessionKey));
        }