Beispiel #1
0
        public byte[] CardSendCommand(byte[] cmd)
        {
            if (ShowLog != null)
            {
                ShowLog("------------------------------\r\n");
                ApduCommand msg = new ApduCommand(cmd);

                if (msg.CmdNote.Trim().StartsWith("建立文件"))
                {
                    CPUFileType cpy = (CPUFileType)(msg.Data[0]);
                    msg.CmdNote += "类型" + cpy.ToString() + "    ";
                }
                string log = $"发送原始命令:{BitConverter.ToString(cmd)} \r\n" + msg.ToString() + "\r\n";



                ShowLog(log);
            }

            byte[] result = this.carder.SendCommand(cmd);

            if (ShowLog != null)
            {
                ApduMsg apduMsg = ApduMsgHelper.GetApduMsg(result);

                string msg = "状态:{0}  信息:{1} 结果:{2} \r\n";

                msg = string.Format(msg, apduMsg.Status, apduMsg.Msg, BitConverter.ToString(apduMsg.ResponseData));

                string log = "接收: " + msg;
                ShowLog(log);
            }
            return(result);
        }
Beispiel #2
0
        public static ApduMsg GetApduMsg(byte[] data)
        {
            ApduMsg reslut = new ApduMsg();

            reslut.ResponseData = data;

            if (data.Length < 2)
            {
                //reslut.Msg = "返回信息长度错误";
                return(reslut);
            }

            //赋值data最后两个字节,作为状态码
            byte[] code = new byte[2];
            Array.Copy(data, data.Length - 2, code, 0, 2);

            if (AllMsgDic.TryGetValue(BitConverter.ToString(code), out reslut))
            {
                reslut = (ApduMsg)reslut.Clone();
            }
            else
            {
                reslut     = new ApduMsg();
                reslut.Msg = "未找到已定义到状态信息";
            }

            reslut.ResponseData = data;


            return(reslut);
        }
Beispiel #3
0
        /// <summary>
        /// 根据文件标识选择文件ID
        /// </summary>
        /// <returns></returns>
        public ApduMsg SelectFileById(ushort fileId)
        {
            string cmd = "00A4000002";

            byte[] data = SendStrCommand(cmd + CPUCardHelper.ConvertoHEX(fileId, 4));
            return(ApduMsg.GetApduByData(data));
        }
Beispiel #4
0
        /// <summary>
        /// 创建二进制文件并写入
        /// </summary>
        /// <param name="flieID"></param>
        /// <param name="fileContent"></param>
        /// <param name="fileLenght">指定文件大小</param>
        /// <returns></returns>
        public ApduMsg CreateAndWriteContent(ushort flieID, byte[] WriteData, string fileName = "FF")
        {
            int fileLenght = WriteData.Length;


            //需要写入的文件
            ApduMsg msg = CreateFile(flieID, CPUFileType.BinFile, fileLenght, fileName);

            if (!msg.IsSuccess)
            {
                //文件已存在 则删除???
                if (msg.Code == "6A-86")
                {
                    msg.Msg += "文件已存在";
                }

                if (msg.Code == "6A-84")
                {
                    msg.Msg += "文件预留空间不足";
                }

                return(msg);
            }
            //创建后,选择文件。有的不会自动选择
            SelectFileById(flieID);

            return(WriteFileContent(flieID, WriteData));
        }
Beispiel #5
0
        /// <summary>
        /// 外部身份验证
        /// </summary>
        /// <param name="Key"></param>
        /// <returns></returns>
        public ApduMsg Auth(byte[] Key)
        {
            if (Key.Length != 8)
            {
                return(new ApduMsg("身份验证Key长度不正确"));
            }
            string RANDOMCMD = "0084000004";


            byte[] Random = SendStrCommand(RANDOMCMD);


            if (Random.Length != 6)
            {
                return(new ApduMsg("返回随机数长度不正确"));
            }

            byte[] Randomdata = new byte[8];

            Array.Copy(Random, 0, Randomdata, 0, 4);

            List <byte> cmdList = new List <byte>();

            cmdList.AddRange(CPUCardHelper.ConverToBytes("00 82 00 00 08"));
            cmdList.AddRange(CPUCardHelper.Encrypt(Randomdata, Key));

            byte[] data = CardSendCommand(cmdList.ToArray());

            return(ApduMsg.GetApduByData(data));
        }
Beispiel #6
0
        public ApduMsg CreateDFFile(ushort fileID, int fileLenght, string FileAccess = "F0F0")
        {
            //        执行指令: 80E0 3F01 0D 38 0520 F0F0 95 FFFF 4444463031
            //说明: 80E0 :指令类别和指令码; 3F01 :文件标识; 0D:长度; 38 :文件类型
            //0520 :文件的空间大小; F0: 读权限; F0: 写权限;
            //            4444463031 :文件名 DDF01 也就是ASCII码了
            //80-E0-00-01-09-38-00-64-F0-F0-95-FF-FF-31
            //80,E0,3F,01,0D,38,05,20,F0,F0,95,FF,FF,44,44,46,30,31,
            //EF01 文件标识
            //07 LC data 长度(07)
            //28 文件类型(二进制)
            //002A 文件长度
            //F00E 读写权限
            //FF 保留
            //80 不支持线路保护

            ApduCommand cmd = new ApduCommand();

            cmd.CLA = 0x80;
            cmd.INS = 0xE0;
            cmd.SetP1P2(fileID);

            //构造一个data  ,长度,权限,
            List <byte> data = new List <byte>();

            //文件类型
            data.Add((byte)CPUFileType.MFDF);
            //文件长度
            data.AddRange(CPUCardHelper.IntConvertTo2Byte(fileLenght));
            //data.Add(0x05);
            //data.Add(0x20);
            //添加读写权限
            //data.AddRange(CPUCardHelper.ConverToBytes(FileAccess));
            data.Add(0xF0);
            data.Add(0xF0);
            //应用文件ID
            data.Add(0x95);
            //保留字
            data.Add(0xFF);
            data.Add(0xFF);

            //使用文件ID当文件夹名称
            //data.AddRange(CPUCardHelper.IntConvertTo2Byte(fileID));
            data.AddRange(GetDFNameByID(fileID));

            //不支持线路保护
            //data.Add(0x80);

            cmd.Data = data.ToArray();

            ApduMsg msg = ApduMsg.GetApduByData(SendStrCommand(cmd));

            if (msg.Code == "6A-86")
            {
                msg.Msg += "(文件已存在)";
            }

            return(msg);
        }
Beispiel #7
0
        public object Clone()
        {
            ApduMsg apdu = new ApduMsg();

            apdu.Code   = this.Code;
            apdu.Msg    = this.Msg;
            apdu.Status = this.Status;
            return(apdu);
        }
Beispiel #8
0
        /// <summary>
        /// 写入文件
        /// </summary>
        /// <param name="fileContent"></param>
        /// <param name="flieID"></param>
        /// <returns></returns>
        public ApduMsg WriteFileContent(ushort flieID, byte[] data)
        {
            //每次传输文件的大小
            int WriteLenght = DefalutReadLenght;

            //将要写入的data数据,按照每次传输的最大的大小切割成data[]的List,用于分组发送
            List <byte[]> arrayData = CPUCardHelper.SplitByteToArray(data, WriteLenght);
            ushort        index     = 0;

            //是否写完
            bool   isWriteOver = true;
            string errorMsg    = "";

            for (int i = 0; i < arrayData.Count; i++)
            {
                ApduMsg msg = WriteContent(index, arrayData[i]);
                if (!msg.IsSuccess)
                {
                    bool isSuccess = false;
                    //如果写入错误为6700,则是长度错误
                    if (msg.Code == "67-00")
                    {
                        errorMsg = "写入长度错误";
                        break;
                    }
                    //如果写入未成功,重试
                    for (int t = 0; t < TryNum; t++)
                    {
                        if (WriteContent(index, arrayData[i]).IsSuccess)
                        {
                            isSuccess = true;
                            break;
                        }
                    }
                    //写入失败后重试后,还失败
                    if (!isSuccess)
                    {
                        isWriteOver = false;
                    }
                }
                index += (ushort)arrayData[i].Length;
            }

            ApduMsg apdu = new ApduMsg();

            if (isWriteOver)
            {
                apdu.Status = ApduMsgStatusEnum.正常;
            }
            else
            {
                apdu.Msg = errorMsg;
            }

            return(apdu);
        }
Beispiel #9
0
        /// <summary>
        /// 删除文件
        /// </summary>
        /// <param name="fileId"></param>
        /// <returns></returns>
        public ApduMsg DeleteFile(ushort fileId)
        {
            //先选择文件后删除
            ApduMsg msg = SelectFileById(fileId);

            if (msg.IsSuccess)
            {
                return(RemoveDF());
            }
            return(msg);
        }
Beispiel #10
0
        private static void InitRecMsgDic() 
        {
            //初始化所有的常用信息到Dic 中缓存

            string[] allLines = DefindMsgCodeArray.Split('\n');

            for (int i = 0; i < allLines.Length; i++)
            {
                string[] allItems = allLines[i].Split(' ');

                if (allItems.Length < 2)
                {
                    continue;
                }
                else
                {
                    try
                    {
                        ApduMsg msg = new ApduMsg();

                        msg.Code = allItems[0];
                        ApduMsgStatusEnum statusEnum;
                        if (Enum.TryParse(allItems[1], out statusEnum))
                        {
                            msg.Status = statusEnum;
                        }
                        else
                        {
                            msg.Status = ApduMsgStatusEnum.其他;
                        }

                        if (allItems.Length >= 3)
                        {
                            msg.Msg = allItems[2];
                        }

                        if (!AllMsgDic.ContainsKey(msg.Code))
                        {
                            AllMsgDic.Add(msg.Code, msg);
                        }

                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine();
                    }

                }
            }

        }
Beispiel #11
0
        /// <summary>
        /// 根据偏移量,读取当前文件
        /// </summary>
        /// <param name="index">偏移量</param>
        /// <param name="lenght">长度</param>
        /// <returns></returns>
        private ApduMsg ReadFile(int index, int lenght)
        {
            //string cmd = "00B0--0000FE";
            string cmd = "00B0--{0}--{1}";

            //读取文件偏移量
            string fileLenghtHexStr = Convert.ToString(index, 16).PadLeft(4, '0');

            //读取的长度
            string lenghtStr = Convert.ToString(lenght, 16).PadLeft(2, '0');

            cmd = string.Format(cmd, fileLenghtHexStr, lenghtStr);
            return(ApduMsg.GetApduByData(SendStrCommand(cmd)));
        }
Beispiel #12
0
        /// <summary>
        /// 根据文件名称选择
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public ApduMsg SelectFileName(byte[] fileName)
        {
            //00A40400 09 A00000000386980701
            byte[] dd = CPUCardHelper.ConverToBytes("00A40400");


            List <byte> result = new List <byte>();

            result.AddRange(dd);
            result.Add((byte)fileName.Length);
            result.AddRange(fileName);
            byte[] cmd  = result.ToArray();
            byte[] data = CardSendCommand(cmd);
            return(ApduMsg.GetApduByData(data));
        }
Beispiel #13
0
        public void ReadGongjiaoka()
        {
            //1pay.sysddf01
            byte[] fileName = new byte[] {
                (byte)'1', (byte)'P', (byte)'A', (byte)'Y',
                (byte)'.', (byte)'S', (byte)'Y', (byte)'S', (byte)'.', (byte)'D', (byte)'D',
                (byte)'F', (byte)'0', (byte)'1'
            };



            string  cmd = "00A40400" + Convert.ToString((byte)fileName.Length, 16).PadLeft(2, '0') + BitConverter.ToString(fileName);
            ApduMsg msg = SendCommand(cmd);

            Console.WriteLine(msg);
        }
Beispiel #14
0
        /// <summary>
        /// 创建文件
        /// </summary>
        /// <param name="fileIDHex">文件标识符2字节</param>
        /// <param name="fileType">枚举文件类型</param>
        /// <param name="fileLenght">文件长度</param>
        /// <param name="fileNameHex">文件名称,十六进制</param>
        /// <param name="FileAccess"></param>
        /// <returns></returns>
        public ApduMsg CreateFile(ushort fileID, CPUFileType fileType, int fileLenght, string FileAccess = "0000")
        {
            //Demo
            //80E0-EF01-07-28-002A-F00E-FF-80
            //EF01 文件标识
            //07 LC data 长度(07)
            //28 文件类型(二进制)
            //002A 文件长度
            //F00E 读写权限
            //FF 保留
            //80 不支持线路保护

            ApduCommand cmd = new ApduCommand();

            cmd.CLA = 0x80;
            cmd.INS = 0xE0;
            cmd.SetP1P2(fileID);

            //构造一个data  ,长度,权限,
            List <byte> data = new List <byte>();

            //文件类型
            data.Add((byte)fileType);
            //文件长度
            data.AddRange(CPUCardHelper.IntConvertTo2Byte(fileLenght));
            //添加读写权限
            data.AddRange(CPUCardHelper.ConverToBytes(FileAccess));
            //添加文件名
            data.AddRange(CPUCardHelper.ConverToBytes("FFFF"));

            //不支持线路保护
            data.Add(0x80);

            cmd.Data = data.ToArray();

            ApduMsg msg = ApduMsg.GetApduByData(SendStrCommand(cmd));

            if (msg.Code == "6A-86")
            {
                msg.Msg += "(文件已存在)";
            }

            return(msg);
        }
Beispiel #15
0
        /// <summary>
        /// 读余额
        /// </summary>
        public ApduMsg GetBalance(bool IsWallet)
        {
            ApduCommand cmd = new ApduCommand();

            cmd.CLA = 0x80;
            cmd.INS = 0x5C;
            //根据文档,01用于电子存折,02用于电子钱包
            if (!IsWallet)
            {
                cmd.P2 = 0x01;
            }
            else
            {
                cmd.P2 = 0x02;
            }

            cmd.LE = 0x4;

            return(ApduMsg.GetApduByData(SendStrCommand(cmd)));
        }
Beispiel #16
0
        /// <summary>
        /// 根据文件标识符,枚举一下所有的文件
        /// </summary>
        /// <returns></returns>
        public string[] GetALlFiles()
        {
            //文档中规定,短文件标识符只能由前五位来确定,也就是最大可用文件标识符为31
            List <string> allFile = new List <string>();

            for (ushort j = 1; j < ushort.MaxValue; j++)
            {
                ApduMsg msg = SelectFileById(j);
                if (msg.Msg != "该文件未找到\r")
                {
                    Console.WriteLine(msg.Msg);
                }

                if (msg.IsSuccess)
                {
                    allFile.Add(Convert.ToString(j, 16).PadLeft(4, '0').ToUpper());
                }
            }
            return(allFile.ToArray());
        }
Beispiel #17
0
        public ApduMsg SelectDFFile(ushort fileId)
        {
            //00-A4-04-00-03-44-46-31-00
            string      cmd      = "00A40400";
            List <byte> listdata = CPUCardHelper.ConverToBytes(cmd).ToList();

            byte[] data = GetDFNameByID(fileId);
            byte   LC   = (byte)(data.Length + 1);

            listdata.Add(LC);
            listdata.AddRange(data);
            listdata.Add(0);

            //ApduCommand adpCMd = new ApduCommand(listdata.ToArray());
            ////adpCMd.LE = 0;



            byte[] Resdata = CardSendCommand(listdata.ToArray());
            return(ApduMsg.GetApduByData(Resdata));
        }
Beispiel #18
0
        /// <summary>
        /// 根据偏移量,写入数据到当前文件
        /// </summary>
        /// <param name="index"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        private ApduMsg WriteContent(ushort index, byte[] data)
        {
            //string fileLenghtHexStr = Convert.ToString(fileLenght, 16).PadLeft(4, '0');

            //00D6-0000-02-0102
            //0000 文件偏移量
            //02 LC,data 长度
            //0102数据
            //FMCOS写文件说明,若P1点高三位为100,则低五位为短的二进制文件标识符。P2为欲写入的文件偏移量
            //若P1点最高位不为1,则P1,P2为欲写入的文件偏移量,所写文件为当前文件

            ApduCommand cmd = new ApduCommand();

            cmd.CLA = 0x00;
            cmd.INS = 0xD6;
            cmd.SetP1P2(index);
            cmd.Data = data;



            //List<byte> array = new List<byte>();
            //array.Add(0x00);
            //array.Add(0xD6);

            ////添加P1 P2参数为文件偏移量

            //array.Add((byte)(index / 256));
            //array.Add((byte)(index % 256));

            ////添加LC,为数据长度
            //array.Add((byte)data.Length);
            ////添加数据
            //array.AddRange(data);
            //ApduMsg msg = ApduMsg.GetApduByData(carder.SendCommand(array.ToArray()));

            ApduMsg msg = ApduMsg.GetApduByData(SendStrCommand(cmd));

            return(msg);
        }
Beispiel #19
0
 /// <summary>
 /// 删除当前文件 删除DF
 /// </summary>
 /// <returns></returns>
 public ApduMsg RemoveDF()
 {
     return(ApduMsg.GetApduByData(SendStrCommand("800E000000")));
 }
Beispiel #20
0
        /// <summary>
        /// 读取文件
        /// </summary>
        /// <param name="flieID">文件名称</param>
        /// <param name="contentOrMsg"></param>
        /// <returns></returns>
        public bool ReadFile(ushort fileId, out byte[] contentOrMsg, out string msgstr)
        {
            // ApduMsg msgd = SelectFileById(fileId);
            //if (!msgd.IsSuccess)
            //{
            //    msgstr = "文件选择失败,可能文件不存在";
            //    return false;
            //}
            contentOrMsg = new byte[0];
            msgstr       = "";


            List <byte> ResultData = new List <byte>();

            int index = 0;


            //由于读取文件时,不能取得二进制文件的大小。所以循环读取,每次读取ReadLenght 长度
            //如果读取结果小于(ReadLenght + 2(状态码))的长度,则认为文件已经读取完毕
            int MAXINDEX   = 300;
            int ReadLenght = DefalutReadLenght;

            for (int i = 0; i < MAXINDEX; i++)
            {
                ApduMsg msg = ReadFile(index, ReadLenght);

                if (msg.IsSuccess)
                {
                    ResultData.AddRange(msg.GetData());

                    //如果给我返回的长度,小于我参数的长度,是否代表已经读到最后
                    if (msg.ResponseData.Length < ReadLenght + 2)
                    {
                        //break;
                    }
                }
                else
                {
                    //根据文档定义,修改读取长度 6Cxx 出错 Le长度错误,实际长度是xx

                    if (msg.StatusCode != null && msg.StatusCode.Length > 0 && msg.StatusCode[0] == 0x6C)
                    {
                        if (msg.StatusCode[1] > 0)
                        {
                            //修改读取长度
                            ReadLenght = msg.StatusCode[1];
                            //重读一遍
                            i--;
                            continue;
                        }
                    }


                    if (msg.Code == "6B-00")
                    {
                        //读取完毕
                        break;
                    }

                    break;
                }
                index += ReadLenght;
            }

            contentOrMsg = ResultData.ToArray();
            return(true);
        }
Beispiel #21
0
 /// <summary>
 /// 选择MF(顶层目录)
 /// </summary>
 /// <returns></returns>
 public ApduMsg SelectMF()
 {
     return(ApduMsg.GetApduByData(SendStrCommand("00A40000023F00")));
     //            return ApduMsg.GetApduByData(SendStrCommand("00,A4,00,00,00"));
 }
Beispiel #22
0
 public ApduMsg SendCommand(string hex)
 {
     return(ApduMsg.GetApduByData(SendStrCommand(hex)));
 }