精华内容
下载资源
问答
  • FM1208
    2020-08-25 10:10:56

    CPU卡内部自带COS,有严格的密钥管理系统。相比M1来说,要复杂的多。我用的是复旦微电子的FM1208 CPU卡,读卡芯片用的是FM1702.FM1702有并口和SPI接口两种方式。NXP的RC500,RC531只有并口接口。用SPI接口,可以省下单片机很多IO口。

    下面是开发过程中我觉得比较重要的地方,总结在下面:

    1、 CPU卡的操作步骤:寻卡-防冲突-选卡-ATS,前面三步和M1操作完全一样,属于ISO14443A前面三层的操作,ATS成功后就进入ISO14443A-4协议层了,也就进入了CPU卡的操作层。

    2、 PPS是可以不做的,只有RATS的返回值表明其接收能力大于PCD的发送即可。PPS用来设置通信时的波特率,通过RATS命令响应数据
    07 77 80 A0 02 47 56可以判断该卡仅支持106K波特率。所以PCD也没有通过PPS指令修改通信波特率的必要了。当然PPS指令重新按106K波特率设置一下也是可以的,RATS以及后续的PCD指令都需要加上CRC的。

    3、 ISO14443-4只规定到PPS指令,后续的指令都需要由CPU卡内部的软件COS来解释,所以卡片完成SELECT,通过RATS和PPS指令后,必须发COS支持的指令。发COS支持的指令一般都需要加CRC的。

    4、 发送取随机数命令00 84 00 00 04,根据块格式规定,除了发送这个指令外,还要发送PCB和CID,即实际发送的字符是0A 01 00 84 00 00 04,0A01这两个字节必须加在每个指令字符串的前面,并且块号不能重复,即如果你连续2次取随机数,需如下发送:0A 01 00 84 00 00 04 ,0B 01 00 84 00 00 04.即第一个字节的最后一位要不断变化。

    5、 取随机数命令可取4字节或8字节。若取随机数命令下条指令为外部认证,则外部认证数据用指定的外部认证密钥解密后与该随机数进行比较。外部认证命令要求CPU卡存在用于外部认证的密钥。在满足该密钥的使用条件,且该密钥未被锁死时才能执行此命令。将命令中的数据用指定外部认证密钥解密,然后与先前产生的随机数进行比较,若一致则表示认证通过,置安全状态寄存器为该密钥规定的后续状态值,错误计数器恢复成初始值,若比较不一致则认证失败,可再试错误数减一,且不改变安全状态寄存器的值。

    6、 MF文件唯一存在,CPU卡复位后,卡片自动选择MF文件为当前文件。任何一个DF在物理上和逻辑上都保持独立,都有自己的安全机制和应用数据。可以通过应用选择实现对其逻辑结构的访问。可以将单个DF文件以及其中一个或多个EF文件当做一个应用。也可以将多个DF以及其中多个EF文件当作一个应用。基本文件EF用于存放用户数据和密钥,存放用户数据的文件称为工作基本文件,在满足一定条件下用户可对文件进行相应的操作。

    KEY文件称为内部基本文件,不可由外部读出,但当获得许可的权限时可在卡内进行相应的密码运算,在满足写的权限时可以修改密钥。KEY文件必须在MF/DF下最先被建立,且一个目录只能有一个KEY文件。KEY文件可以存多个口令密钥,外部认证密钥,DES运算密钥,每个密钥为一个TLV格式的可变长记录,记录的长度为密钥数据长度加8,3DES密钥长度为24字节,DES密钥记录的长度为16字节。

    7、 外部认证

    A、取随机数可以取4字节,也可以取8字节,如果是4字节,则在后面加上4字节0,也就是参与加密运算的随机数是8字节。
    B、 外部认证所用的加密算法是DES/3DES算法
    C、 密钥是指外部认证密钥
    D、如果密钥的长度是8字节,则适用DES算法,如果密钥长度为16字节,则适用3DES算法。

    8、 一般CPU卡提供商提供CPU卡时,已经对CPU卡进行过初始化,即CPU卡上已经建立了主文件MF及主密钥文件(MF下的KEY文件),主密钥文件中也写入了初始化CPU卡主控密钥。在对CPU卡建立特定的卡结构及写入密钥和数据之前,程序设计中的第一步应该对CPU卡进行外部认证。外部认证所使用的密钥正是初始CPU卡主控密钥。当完成外部认证后,接下来最好是擦除CPU卡上已有的结构,然后开始重新建立CPU卡结构。

    9、 文件标识符是文件的标识代码,用2个字节表示,同一目录下的文件标识符必须是唯一的,MF的文件标识符是3F00。短文件标识符选择只能用5位来决定。所以可选择的最大文件标识符是31。选择文件后,只要文件存在,该文件就被置为当前文件,以后可以不用选择而直接对该文件进行操作。文件类型在建立文件时规定。

    10、 删除MF文件后,选择MF会返回FA 01 01,程序要一直发送FA 01 01给1208,直到收到0A 0B开头的数据。如果MF下没有密钥文件,建立KEY文件不需外部认证。

    11、 在多应用卡中,MF下通常包含多个DF,这里的MF就是一个典型的DDF,为了维护管理DDF下所有的DF,在每一个DDF下一般可以包含一个系统文件(DIR),记录所有子DF的入口,如果只有一个ADF应用,不需建立DIR文件。

    12、 DF文件短标识符,当高三位为000时,为DDF,当高三位为100时,为ADF的短文件标识符,在建立目录文件时,要指定2字节文件标识符,短文件标识符,文件名。短文件标识符要在1-31之间,和文件标识符没有关系。在卡片出厂时建立MF,MF的短文件标识符应为01,因为建立MF下密钥文件使用的DF短标识符是01。所以自建一个DF,短文件标识符应定义为02或其它值。同一目录下的文件标识符必须是唯一的。

    13、 密钥标识,如果该目录下某类型密钥只有一个,则其密钥标识原则上应为00,否则应从01顺序开始。

    14、 增加权限:在当前目录下创建新文件的权限

    激活权限:激活失效安全机制的权限

    终止权限:永久终止的权限,对于MF来说,标识卡锁定,对于ADF来说,表示当前应用永久锁定,即应用失效。

    读权限:对EF文件的内容的读操作权限

    写权限:对EF文件内容的写操作权限

    安装权限:安装密钥和密码的权限

    使用权限:表示使用密钥或密码的权限

    修改权限:修改密钥或密码的权限

    解锁权限:解锁密码PIN的权限,此权限只有PIN才有

    15、 安全机制是指安全状态的改变所采用的方法和手段以及安全属性和安全状态之间的控制关系,COS命令在执行过程中,首先要检查COS环境所处的安全状态是否符合执行命令需求的安全属性,假设当前COS所处的是安全状态A,执行COS命令安全属性要求为安全状态
    B,在执行COS命令前要通过安全机制涉及安全提升方法,将安全状态提升到安全状态B。

    16、 内部认证是用读卡设备来认证卡,保证卡的合法性,内部认证可以防止伪造的卡在读卡设备上进行操作。

    外部认证是用卡来认证外部读卡设备的合法性,外部认证可以防止恶意对卡进行操作,读取或更改卡内信息。外部认证还可以改变卡的安全状态,一般卡内存储了多个外部认证密钥,每个外部认证密钥多能改变的安全状态不一样,在进行外部认证时,必须通过密钥索引参数选择对应的外部认证密钥完成外部认证。

    CPU卡和读卡设备存放吸纳沟通的密钥

    外部认证步骤:

    A、CPU卡产生一个8进制随机数送给读卡器,CPU卡临时保存随机数在卡内

    B、 读卡器程序用密钥计算随机数,得到随机数密文

    C、 读卡器程序把8字节随机数密文送给CPU卡

    D、CPU卡在卡片内部解密8字节随机数得到随机数明文

    E、 CPU卡在卡片内部把解密后的随机数和步骤A中临时存放的随机数对比,若相等,则外部认证密钥成功

    外部认证是CPU卡认证读卡器

    内部认证步骤:

    A、读卡器产生一个8字节随机数,发送给CPU卡,读卡器临时保存这个随机数。

    B、 CPU卡用内部认证密钥计算这个随机数,得到8字节随机数密文。

    C、 CPU卡把随机数密文发给读卡器

    D、读卡器解密8字节随机数密文得到随机数明文

    E、 读卡器把解密后的随机数和步骤A中产生的随机数对比,若相等,则内部认证成功。

    内部认证是读卡器认证CPU卡

    更多相关内容
  • 通过51单片机控制RC522操作CPU卡,前面PcdRequest(寻...详情请查看FM1208发卡命令以及ISO1443协议。该程序是通过串口与RC522进行通信的,如使stm32开发使用到SPI接口的只需要改发送接收函数即可,程序都是大同小异的。
  • 该文档很好地讲解了CPU卡的激活,密钥验证,操作CPU内部等等。有详细的发卡指令,有兴趣的小伙伴可以下载来学习,对CPU卡的开发很有帮助。
  • FM1208系列非接触CPU卡是由上海复旦微电子股份有限公司自主研发的CPU卡芯片和COS制作而成,具有自主知识产权,是国内第一款通过银行卡检测中心PBOC2.0标准测试的单界面非接触CPU卡。该文档讲解FM1208的基础知识,...
  • 摘要 在对非接触逻辑加密卡Mifare和非接触CPU卡比较的基础上,介绍我国自主研发的复旦FM1208非接触CPU卡的特点及性能,并给出读写FM1208卡硬件系统的配置及选型,以及软件设计的参考流程,为已经大量使用的Mifare卡...
  • Delphi调用DLL动态库函数读写fm1208CPU卡示例源码,源码中包括以下功能: 1、激活感应区上的CPU卡; 2、CPU卡初始化; 3、在CPU卡内创建新的文件; 4、更件CPU卡内已创文件的密码; 5、读、写CPU卡内指定的文件; ...
  • 复旦卡FM1208,非常不错的读写例子程序,方便对复旦卡FM1208不熟悉的人学习用,给有需要的人下载。
  • mfrc522 读取 cpu IC FM1208
  • FM1208-CPU卡Python示例源码.rar,FM1208-CPU卡Python示例源码,运行Pythonfm1208RW.bat,Pythonfm1208RW.py,重要说明.txt,OUR_MIFARE.dll
  • FM1208-CPU卡Java_Jna示例源码.rar,FM1208-CPU卡Java_Jna示例源码,Java_Jna_RWFm1208Cpu.iml,src,RWFm1208Cpu.java,.idea,misc.xml,uiDesigner.xml,workspace.xml,$PRODUCT_WORKSPACE_FILE$,.name,encodings.xml,...
  • RC522_串口操作FM1208

    2019-03-12 14:46:17
    RC522_串口操作FM1208,这个是51单片机通过串口操作RC522读写FM1208CPU卡的底层,如果你的是SPI接口,只要把发送数据和接收数据的串口函数改下就可以
  • FM1208CPU卡发卡命令流

    2014-01-17 21:15:33
    FM1208CPU卡发卡命令流,对于开发CPU应该很有用
  • C#调用DLL动态库函数读写FM1208CPU卡示例源码,包括以下功能 : 1、激活感应区上的CPU卡; 2、CPU卡初始化; 3、在CPU卡内创建新的文件; 4、更件CPU卡内已创文件的密码; 5、读、写CPU卡内指定的文件; 函数说明:...
  • 复旦CPU卡FM1208开发

    2021-09-23 08:24:06
    //取随机数 res = FM1208_GetChallenge(ran_number_long, ran_number); if (res == 0x9000) { printf("random number generated: \r\n"); for(int i = 0; i ; i++) printf ( "%x " , ran_number[i]); ...

    RC522与STM32F103通信

    void InitRc522(void)
    {
            Spi_IO_Init();
    	    PcdReset();
            PcdAntennaOff();
            delay_ms(2);  
            PcdAntennaOn();
            M500PcdConfigISOType( 'A' );
    }
    
    

    我使用的是SPI通信的方式与RC522进行通信,其中天线的初始化是必须的。通信成功后可以进行后续的配置。

    寻卡、防冲突、完成选卡

    void RC522_Config ( void )
    {                                                                                       
    	uint8_t ucStatusReturn;    		//返回状态                                       
    	uint8_t flag_station = 1;		//跳出函数的标志位
    
      while ( flag_station )
      { 
    		/* 寻卡(方式:范围内全部),第一次寻卡失败后再进行一次,寻卡成功时卡片序列传入数组ucArray_ID中 */
    		if ( ( ucStatusReturn = PcdRequest ( PICC_REQALL, ucArray_ID ) ) != MI_OK )
    			ucStatusReturn = PcdRequest ( PICC_REQALL, ucArray_ID );		   
    
    		if ( ucStatusReturn == MI_OK  )
    		{
    			/* 防冲突操作,被选中的卡片序列传入数组ucArray_ID中 */
    			if ( PcdAnticoll ( ucArray_ID ) == MI_OK )
    			{
    			//	sprintf ( id_cpu, "The Card ID is: %02X%02X%02X%02X", ucArray_ID [ 0 ], ucArray_ID [ 1 ], ucArray_ID [ 2 ], ucArray_ID [ 3 ] );				
    			//	printf ("%s\r\n", id_cpu ); 
    				if ( PcdSelect ( ucArray_ID ) == MI_OK )
    					{
    						printf ("\nRC522 is Ready!\n");
    						flag_station = 0;													
    					}							
    			}
    		}
    
      }
    }
    

    这里完成后就已经完成对复旦CPU卡的通信了,后面可以通过命令进行操作,接下来的发卡流程可以参考复旦微电子CPU卡发卡流程
    这里博主已经写的很详细,我简略提一下其中我碰到的问题。

    DES算法进行随机数加密

    在进行外部认证进行随机数加密的时候,我发现开发手册里是没有给出DES加密的指令,因此当时是自己找了一个可以用的DES加密算法对随机数进行加密,然后将加密后的八字节数送入外部认证命令当中。

    	//取随机数
    	res = FM1208_GetChallenge(ran_number_long, ran_number);
    	if (res == 0x9000) {	
    		printf("random number generated: \r\n");
    		for(int i = 0; i < 8; i++) 
    			printf ( "%x " , ran_number[i]);
    		printf("\r\n");
    	}
    	else
    		printf ( "random get failed!, error code: %x\r\n", res);
    		
    	memset(des_encrypted_code, 0x00, 8);  //清0
    	
    	//其中newkey是我自己写入的密钥,卡的初始密钥为八字节的FFFFFFFF。
    	DES_Encrypt(ran_number, new_key, des_encrypted_code);
    	printf("des encrypted code: \r\n");
    	for(int i = 0; i < 8; i++) 
    			printf ( "%x " , des_encrypted_code[i]);
    	printf("\r\n");
    	
    	//外部认证
    	res = FM1208_External_Authenticate(0x00, des_encrypted_code, g_cReceBuf);
    	if (res == 0x9000) {
    		printf("card authenticated.\r\n");
    	}
    	else {
    		printf("Authenticate failed, error code: %x\r\n", res);
    	}
    

    二进制文件的读写问题

    当我外部认证完成,创建完二进制文件后,发现当外部认证失败的时候,二进制文件也同样可以进行读写,经过一段时间的研究后,发现可以通过PIN加密,来实现对读写操作的权限设置。这里可以先看明白手册中的FMCOS 独特的安全体系,然后可以进行相应的指令配置,就可以设置PIN进行安全认证了。

    展开全文
  • FM1208_智能卡

    2016-01-04 17:29:05
    智能卡fm1208的简单测试代码 ,欢迎使用 下载
  • 符合PBOC(中国人民银行)标准的CPU卡、PSAM卡操作说明
  • FM1208_ds_chs.pdf

    2021-11-24 16:16:32
    CPU卡FM1208手册
  • C# 读写FM1208 CPU卡源码

    2021-12-16 10:03:26
    C#调用DLL动态库读写FM1208 CPU卡,初始化卡、创建文件、更改文件密码、读写文件等操作。

    //本示例使用的发卡器淘宝链接: https://item.taobao.com/item.htm?spm=a1z10.5-c.w4002-17663462238.11.1f50789eN01bfi&id=615391857885https://item.taobao.com/item.htm?spm=a1z10.5-c.w4002-17663462238.11.1f50789eN01bfi&id=615391857885

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;  //调用动态库一定要加入这个引用
    
    namespace C井源代码CPU卡操作
    {
        public partial class Form1 : Form
        {
          
    
            public Form1()
            {
                InitializeComponent();           
            }
    
            public byte NEWKEYR = 0x00;   //'更改只读密码
            public byte NEWKEYWR = 0x01;  //'更改读写密码
    
            public byte OLDKEYR = 0x00;   //'用只读密码认证
            public byte OLDKEYWR = 0x02;  //'用读写密码认证
    
            //------------------------------------------------------------------------------------------------------------------------------------------------------
            //寻卡
            [DllImport("OUR_MIFARE.dll", EntryPoint = "piccrequest")]
            static extern byte piccrequest(long serial);
            //------------------------------------------------------------------------------------------------------------------------------------------------------
            //轻松读卡
            [DllImport("OUR_MIFARE.dll", EntryPoint = "piccreadex")]
            static extern byte piccreadex(byte ctrlword, byte[] serial, byte area, byte keyA1B0, byte[] picckey, byte[] piccdata0_2);
            //参数:说明
            //ctrlword:控制字
            //serial:卡序列号数组,用于指定或返回卡序列号
            //area:指定读卡区号
            //keyA1B0:指定用A或B密码认证,一般是用A密码,只有特殊用途下才用B密码,在这不做详细解释。
            //picckey:指定卡密码,6个字节,卡出厂时的初始密码为6个0xff
            //piccdata0_2:用于返回卡该区第0块到第2块的数据,共48个字节.
            //------------------------------------------------------------------------------------------------------------------------------------------------------
            //轻松写卡
            [DllImport("OUR_MIFARE.dll", EntryPoint = "piccwriteex")]
            static extern byte piccwriteex(byte ctrlword, byte[] serial, byte area, byte keyA1B0, byte[] picckey, byte[] piccdata0_2);
            //参数:说明
            //ctrlword:控制字
            //serial:卡序列号数组,用于指定或返回卡序列号
            //area:指定读卡区号
            //keyA1B0:指定用A或B密码认证,一般是用A密码,只有特殊用途下才用B密码,在这不做详细解释。
            //picckey:指定卡密码,6个字节,卡出厂时的初始密码为6个0xff
            //piccdata0_2:用于返回卡该区第0块到第2块的数据,共48个字节.
            //------------------------------------------------------------------------------------------------------------------------------------------------------
            //修改卡单区的密码
            [DllImport("OUR_MIFARE.dll", EntryPoint = "piccchangesinglekey")]
            static extern byte piccchangesinglekey(byte ctrlword, byte[] serial, byte area, byte keyA1B0, byte[] piccoldkey, byte[] piccnewkey);
            //参数:说明
            //ctrlword:控制字
            //serial:卡序列号数组,用于指定或返回卡序列号
            //area:指定读卡区号
            //keyA1B0:指定用A或B密码认证,一般是用A密码,只有特殊用途下才用B密码,在这不做详细解释。
            //piccoldkey://旧密码
            //piccnewkey://新密码.
            //------------------------------------------------------------------------------------------------------------------------------------------------------
            //外部函数声明:让设备发出声响
            [DllImport("OUR_MIFARE.dll", EntryPoint = "pcdbeep", CallingConvention = CallingConvention.StdCall)]
            static extern byte pcdbeep(Int32 xms);//xms单位为毫秒 
            //------------------------------------------------------------------------------------------------------------------------------------------------------    
            //读取设备编号,可做为软件加密狗用,也可以根据此编号在公司网站上查询保修期限
            [DllImport("OUR_MIFARE.dll", EntryPoint = "pcdgetdevicenumber")]
            static extern byte pcdgetdevicenumber(byte[] devicenumber);//devicenumber用于返回编号 
            //------------------------------------------------------------------------------------------------------------------------------------------------------
            //'CPU卡寻卡及将卡复位到14443A-4的指令状态
            [DllImport("OUR_MIFARE.dll", EntryPoint = "cpurequest")]
            static extern byte cpurequest(byte[] serial, byte[] param, byte[] cosver, byte[] code);
            //------------------------------------------------------------------------------------------------------------------------------------------------------
            //初始化函数,(ctrlword是否需要先清空卡,不需要清空的话,可以需输入卡密码,卡密码长度)ctrlword_0是否先清空卡,分配空间(字节数),
            //Public Declare Function cpursinit Lib "OUR_MIFARE.dll" (ByVal ctrlword As Byte, ByVal key As Long, ByVal keylen As Byte, ByVal customsize As Long) As Byte
            [DllImport("OUR_MIFARE.dll", EntryPoint = "cpursinit", CallingConvention = CallingConvention.StdCall)]
            static extern byte cpursinit(byte ctrlword, byte[] key, byte[] keylen, Int32 customsize);
            //------------------------------------------------------------------------------------------------------------------------------------------------------
            //增加文件(文件序号0~5,文件只读密码:长度,文件读写密码,长度,分配空间) 
            //Public Declare Function cpursfileadd Lib "OUR_MIFARE.dll" (ByVal fileno As Byte, ByVal readonlykey As Long, ByVal readonlykeylen As Byte, ByVal writekey As Long, ByVal writekeylen As Byte, ByVal customsize As Long) As Byte
            [DllImport("OUR_MIFARE.dll", EntryPoint = "cpursfileadd", CallingConvention = CallingConvention.StdCall)]
            static extern byte cpursfileadd(byte fileno, byte[] readonlykey, byte[] readonlykeylen, byte[] writekey, byte[] writekeylen, Int32 customsize);
            //------------------------------------------------------------------------------------------------------------------------------------------------------
            //'修改文件密码,修改后,请妥慎记住,否则该文件将无法再用
            //Public Declare Function cpursfilekeychg Lib "OUR_MIFARE.dll" (ByVal fileno As Byte, ByVal keytype As Byte, ByVal oldkey As Long, ByVal oldkeylen As Byte, ByVal newkey As Long, ByVal newkeylen As Byte) As Byte
            [DllImport("OUR_MIFARE.dll", EntryPoint = "cpursfilekeychg", CallingConvention = CallingConvention.StdCall)]
            static extern byte cpursfilekeychg(byte fileno, byte keytype, byte[] oldkey, byte[] oldkeylen, byte[] newkey, byte[] newkeylen);
            //------------------------------------------------------------------------------------------------------------------------------------------------------
            //'修改卡密码,卡密码和文件没有任何关系,卡密码只是用来清空卡,读和写文件是无效的。
            //Public Declare Function cpurscardkeychg Lib "OUR_MIFARE.dll" (ByVal oldkey As Long, ByVal oldkeylen As Byte, ByVal newkey As Long, ByVal newkeylen As Byte) As Byte
            [DllImport("OUR_MIFARE.dll", EntryPoint = "cpurscardkeychg", CallingConvention = CallingConvention.StdCall)]
            static extern byte cpurscardkeychg(byte fileno, byte[] readonlykey, byte[] readonlykeylen, byte[] writekey, byte[] writekeylen, Int32 customsize);
            //------------------------------------------------------------------------------------------------------------------------------------------------------
            //读文件数据(文件序号,读写密码,密码长度,读取起始位置,读取长度,读出内容)
            //Public Declare Function cpursfiledataread Lib "OUR_MIFARE.dll" (ByVal fileno As Byte, ByVal keytype As Byte, ByVal key As Long, ByVal keylen As Byte, ByVal startaddr As Long, ByVal databuf As Long, ByVal datalen As Long) As Byte
            [DllImport("OUR_MIFARE.dll", EntryPoint = "cpursfiledataread", CallingConvention = CallingConvention.StdCall)]
            static extern byte cpursfiledataread(byte fileno, byte keytype, byte[] rwkey, byte[] rwkeylen, Int32 startaddr, byte[] databuf, Int32 datalen);
            //------------------------------------------------------------------------------------------------------------------------------------------------------
            //写文件数据(文件序号,文件读写密码,密码长度,写入起始位置,写入长度,写入内容)
            //Public Declare Function cpursfiledatawrite Lib "OUR_MIFARE.dll" (ByVal fileno As Byte, ByVal keytype As Byte, ByVal key As Long, ByVal keylen As Byte, ByVal startaddr As Long, ByVal databuf As Long, ByVal datalen As Long) As Byte
            [DllImport("OUR_MIFARE.dll", EntryPoint = "cpursfiledatawrite", CallingConvention = CallingConvention.StdCall)]
            static extern byte cpursfiledatawrite(byte fileno, byte keytype, byte[] rwkey, byte[] rwkeylen, Int32 startaddr, byte[] databuf, Int32 datalen);
            //------------------------------------------------------------------------------------------------------------------------------------------------------
            //修改卡密码,卡密码和文件没有任何关系,卡密码只是用来清空卡,读和写文件是无效的。
            //Public Declare Function cpurscardkeychg Lib "OUR_MIFARE.dll" (ByVal oldkey As Long, ByVal oldkeylen As Byte, ByVal newkey As Long, ByVal newkeylen As Byte) As Byte
            [DllImport("OUR_MIFARE.dll", EntryPoint = "cpurscardkeychg", CallingConvention = CallingConvention.StdCall)]
            static extern byte cpurscardkeychg(byte[] oldkey, byte[] oldlen, byte[] newkey, byte[] newlen);
    
    
            private void Form1_Load(object sender, EventArgs e)
            {
                comboBox1.SelectedIndex = 0;
                comboBox2.SelectedIndex = 0;
                comboBox3.SelectedIndex = 0;
                comboBox4.SelectedIndex = 0;
                comboBox5.SelectedIndex = 0;
                comboBox6.SelectedIndex = 0;
    
            }
    
            private static bool checkpassw(string paswstr, byte[] cardmima, byte[] mimalen)   //判断密码是否合法
            {
                int i;
                byte isbyteyesno;
                paswstr = paswstr.Trim(); 
                string[] macsz = paswstr.Split(new char[2] { ' ', ' ' });//分割字符串            
    
                mimalen[0] = Convert.ToByte(macsz.Length);
                try
                {
                    for (i = 0; i <=Convert.ToInt16(mimalen[0])-1; i++)
                    {
                        isbyteyesno = Convert.ToByte(macsz[i], 16);
                        cardmima[i] = Convert.ToByte(macsz[i], 16);       
                    }
                    return true;
                }
                catch
                {
                    return false;
                }
            }
    
            private static byte messdisp(byte errno)
            {
                switch (errno)
                {
                    case 0:
                         MessageBox.Show("操作成功!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); 
                         break;
                    case 8:
                         MessageBox.Show("请重新拿开卡后再放到感应区!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); 
                         break;
                    case 50:
                         MessageBox.Show("RATS错误,厂家调试代码,用户不需理会!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); 
                         break;
                    case 51:
                         MessageBox.Show("PPS错误,厂家调试代码,用户不需理会!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); 
                         break;
                    case 52:
                         MessageBox.Show("已进入了14443-4协议状态,可进行CPU卡功能所有操作了!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); 
                         break;
                    case 53:
                         MessageBox.Show("CPU卡功能通讯错误!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); 
                         break;
                    case 54:
                         MessageBox.Show("数据不足,需要接着发送未完成的数据至卡上!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); 
                         break;
                    case 55:
                         MessageBox.Show("发送ACK指令给卡,让卡接着发送数据回来!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); 
                         break;
                    case 56:
                         MessageBox.Show("清空根目录失败!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); 
                         break;
                    case 57:
                         MessageBox.Show("卡片不支持功能!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); 
                         break;
                    case 58:
                         MessageBox.Show("卡片初始化失败!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); 
                         break;
                    case 59:
                         MessageBox.Show("分配的空间不足!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); 
                         break;
                    case 60:
                         MessageBox.Show("本次操作的实体已存在!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); 
                         break;
                    case 61:
                         MessageBox.Show("无足够空间!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); 
                         break;
                    case 62:
                         MessageBox.Show("文件不存在!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); 
                         break;
                    case 63:
                         MessageBox.Show("权限不足,有可能是用只读密码认证,导致无法更改读写密码或无法写文件!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); 
                         break;
                    case 64:
                         MessageBox.Show("密码不存在,或密钥文件未创建!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); 
                         break;
                    case 65:
                         MessageBox.Show("传送长度错误!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); 
                         break;
                    case 66:
                         MessageBox.Show("Le错误,即接收的数据长度指定过大!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); 
                         break;
                    case 67:
                         MessageBox.Show("功能不支持或卡中无MF 或卡片已锁定!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); 
                         break;
                    case 68:
                         MessageBox.Show("密码认证错识次数过多,该密码已被锁死!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); 
                         break;
                    case 86:
                         MessageBox.Show("更改后的密码长度必须和创建时的长度一致!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); 
                         break;
                    case 87:
                         MessageBox.Show("应用目录不存在!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); 
                         break;
                    case 88:
                         MessageBox.Show("应用文件不存在!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); 
                         break;
                    case 89:
                         MessageBox.Show("文件号不能超过5!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); 
                         break;
                    case 90:
                         MessageBox.Show("读取文件时返回的长度不足,数据可能不正确!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); 
                         break;
                    case 91:
                         MessageBox.Show("一次读文件的长度不能超过255!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); 
                         break;
                    case 92:
                         MessageBox.Show("一次写文件的长度不能超过247!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); 
                         break;
                    case 70:
                    case 71:
                    case 72:
                    case 73:
                    case 74:
                    case 75:
                    case 76:
                    case 77:
                    case 78:
                    case 79:
                    case 80:
                    case 81:
                    case 82:
                    case 83:
                    case 84:
                    case 85:
                         MessageBox.Show("密码错误,剩余次数为"+Convert .ToString (errno-70)+",如果为0,该密码将锁死,无法再认证", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); 
                         break;
                    default:
                         MessageBox.Show("操作失败,返回错误代码!" + Convert.ToString(errno), "警告", MessageBoxButtons.OK, MessageBoxIcon.Error);
                         break; 
    
    
                }
                return 0;
    
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                byte status;  //'存放返回值
                byte i;
    
                byte[] mypiccserial = new byte[4];//'卡序列号            
                byte[] myparam= new byte[4];
    
                byte[] myver = new byte[1];
                byte[] mycode=new byte[1];
                double cardhao;
                string cardhohex="";
                string parastr = "";
                string aaa;
                
                status = cpurequest(mypiccserial, myparam, myver, mycode);
                switch (status)
                {
                    case 0 :                   
    
                    case 52 :
                            cardhao = mypiccserial[3];
                            cardhao = cardhao * 256;
                            cardhao = cardhao + mypiccserial[2];
                            cardhao = cardhao * 256;
                            cardhao = cardhao + mypiccserial[1];
                            cardhao = cardhao * 256;
                            cardhao = cardhao + mypiccserial[0];
                            textBox1.Text =Convert.ToString (cardhao);
    
                            for (i = 0; i <= 3; i++)
                            {
                                aaa = "000" + string.Format("{0:X}", mypiccserial[i]);
                                aaa = aaa.Substring(aaa.Length - 2);
                                if (i < 3)
                                {
                                    cardhohex = cardhohex + aaa + "-";
                                }
                                else
                                { cardhohex = cardhohex + aaa; }
                            }
                         
                            for (i = 0; i <= 3; i++)
                            {
                                aaa = "000" + string.Format("{0:X}", myparam[i]);
                                aaa = aaa.Substring(aaa.Length - 2);
                                if (i < 3)
                                {
                                    parastr = parastr + aaa + "-";
                                }
                                else
                                { parastr = parastr + aaa; }
                            }
    
                            status = pcdbeep(20);
                            MessageBox.Show("复位CPU卡成功,CPU卡进入14443A-4的协议模式,可以接着重复操作第二步进行调试了。\r\n" + "卡号:" + cardhohex + ",参数:" + parastr + ",厂商代码(复旦为90):" + string.Format("{0:X}", mycode[0]), "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
    
                            break;
                    case 8:
                            MessageBox.Show("未寻到感应区上的CPU卡,请重新拿开卡后再放到感应区!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            break;
                    default :
                            MessageBox.Show("操作失败,返回错误代码!" + Convert.ToString(status), "警告", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            break;       
                }
    
    
            }
    
            private void button2_Click(object sender, EventArgs e)
            {
          
             byte i;
             byte[] mylen=new byte[1];
             Int32 spacesize;
             byte status;
             byte[] keybuf=new byte[20];//'卡密码   
    
             if (!checkpassw(textBox2.Text, keybuf, mylen))
             {
                 MessageBox.Show("请输入正确的卡密码!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Error);
                 textBox2.Select();
                 return;
             }
    
             spacesize =Convert.ToInt32(spacesize1.Value);
             if (spacesize1.Value < 1)
             {
                 MessageBox.Show("应用空间大小为0,请重新输入!" , "警告", MessageBoxButtons.OK, MessageBoxIcon.Error);
                 spacesize1.Select();
                 return;
             }
    
             if (checkBox1.Checked )
             { i = 1; }
             else { i = 0; }
    
             status = cpursinit(i, keybuf, mylen, spacesize);
             switch (status)
             {
                 case 0:
                      status = pcdbeep(20);
                      MessageBox.Show("初始化卡成功", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                      break;
                 default :
                      status=messdisp(status);
                      break; 
             }
    
    
            }
    
            private void button3_Click(object sender, EventArgs e)
            {
                Form2 f2 = new Form2();
                f2.Owner = this;
                f2.Show();
            }
    
            private void button5_Click(object sender, EventArgs e)
            {
                byte i;
                Int32 spacesize; //文件大小
                byte status;
                byte[] readkeylen = new byte[1];            
                byte[] readkeybuf = new byte[20];//'只读密码   
                byte[] rwkeylen = new byte[1];
                byte[] rwkeybuf = new byte[20];//'读写密码   
    
                if (!checkpassw(textBox4.Text, readkeybuf, readkeylen))
                {
                    MessageBox.Show("请输入正确的只读密码!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    textBox4.Select();
                    return;
                }
    
                if (!checkpassw(textBox3.Text, rwkeybuf, rwkeylen))
                {
                    MessageBox.Show("请输入正确的读写密码!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    textBox3.Select();
                    return;
                }
    
                spacesize =Convert.ToInt32(filesize1.Value);
                if (spacesize1.Value < 1)
                {
                    MessageBox.Show("文件大小为0,请重新输入!" , "警告", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    filesize1.Select(); 
                    return;
                }
    
                i =Convert.ToByte (comboBox1.SelectedIndex);
    
                status = cpursfileadd(i, readkeybuf, readkeylen, rwkeybuf, rwkeylen, spacesize);
                switch (status)
                {
                    case 0:
                        status = pcdbeep(20);
                        MessageBox.Show("创建文件成功", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        break;
                    default:
                        status = messdisp(status);
                        break;
                }
    
    
            }
    
            private void button4_Click(object sender, EventArgs e)
            {
                byte fino;
                byte i=0;
                byte status;
                byte[] oldkeylen = new byte[1];
                byte[] oldkeybuf = new byte[20];//'旧密码   
                byte[] newkeylen = new byte[1];
                byte[] neweybuf = new byte[20];//'新密码   
    
    
                if (!checkpassw(textBox5.Text, oldkeybuf, oldkeylen))
                {
                    MessageBox.Show("请输入正确的认证密码!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    textBox5.Select();
                    return;
                }
    
                if (!checkpassw(textBox6.Text, neweybuf, newkeylen))
                {
                    MessageBox.Show("请输入正确的新密码!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    textBox6.Select();
                    return;
                }
    
                 //   '需要更改的密码类型
                if( comboBox4.SelectedIndex== 0)
                {i = NEWKEYR;}  //'更改只读密码
                else{i = NEWKEYWR;} //'更改读写密码
            
                //    '用来认证的密码类型
                if( comboBox3.SelectedIndex== 0)
                {i=Convert.ToByte(i+OLDKEYR);}  //'用只读密码来认证
                else{i =Convert.ToByte(i + OLDKEYWR);} //'用读写密码来认证
    
                fino =Convert.ToByte(comboBox2.SelectedIndex);
                status = cpursfilekeychg(fino, i, oldkeybuf, oldkeylen, neweybuf, newkeylen);
                switch (status)
                {
                    case 0:
                        status = pcdbeep(20);
                        MessageBox.Show("修改文件密码成功", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        break;
                    default:
                        status = messdisp(status);
                        break;
                }
            }
    
            private void button6_Click(object sender, EventArgs e)
            {
                byte fino;
                byte i = 0;
                byte status;
                Int32 staradd;
                Int32 datalen;
                byte[] rwkeylen = new byte[1];
                byte[] rwkeybuf = new byte[20];//'旧密码   
                byte[] rwbuf = new byte[8000];//'新密码   
                string strls = "";
                string recestr = "";
    
                if (!checkpassw(textBox7.Text, rwkeybuf, rwkeylen))
                {
                    MessageBox.Show("请输入正确的认证密码!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    textBox7.Select();
                    return;
                }
    
                fino = Convert.ToByte(comboBox5.SelectedIndex);
    
                staradd = Convert.ToInt32(staradd1.Value);
    
                datalen = Convert.ToInt32(datalen1.Value); 
    
                //    '用来认证的密码类型
                if (comboBox6.SelectedIndex == 0)
                { i =  OLDKEYR; }  //'用只读密码来认证
                else { i =  OLDKEYWR; } //'用读写密码来认证
    
                status = cpursfiledataread(fino, i, rwkeybuf, rwkeylen, staradd, rwbuf, datalen);
                
                switch (status)
                {
                    case 0:
                        for (i = 0; i <= datalen; i++)
                        {
                            strls = "000" + string.Format("{0:X}", rwbuf[i]);
                            strls = strls.Substring(strls.Length - 2);
                            recestr = recestr + strls + " ";
                        }
                        textBox8.Text = recestr;
                        status = pcdbeep(20);
                        MessageBox.Show("读取数据成功!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        break;
                    default:
                        status = messdisp(status);
                        break;
                }
    
            }
    
            private void button7_Click(object sender, EventArgs e)
            {
                byte fino;
                byte i = 0;
                byte status;
                Int32 staradd;
                Int32 datalen;
                byte[] rwkeylen = new byte[1];
                byte[] rwkeybuf = new byte[20];//'旧密码   
                byte[] rwbuf = new byte[8000];//'新密码   
    
                if (!checkpassw(textBox8.Text, rwbuf, rwkeylen))
                {
                    MessageBox.Show("请输入正确的数据!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    textBox8.Select();
                    return;
                }
    
                if (!checkpassw(textBox7.Text, rwkeybuf, rwkeylen))
                {
                    MessageBox.Show("请输入正确的认证密码!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    textBox7.Select();
                    return;
                }
    
                fino = Convert.ToByte(comboBox5.SelectedIndex);
    
                staradd = Convert.ToInt32(staradd1.Value);
    
                datalen = Convert.ToInt32(datalen1.Value);
    
                //    '用来认证的密码类型
                if (comboBox6.SelectedIndex == 0)
                { i = OLDKEYR; }  //'用只读密码来认证
                else { i = OLDKEYWR; } //'用读写密码来认证
    
                status = cpursfiledatawrite(fino, i, rwkeybuf, rwkeylen, staradd, rwbuf, datalen);
    
                switch (status)
                {
                    case 0:
                        status = pcdbeep(20);
                        MessageBox.Show("写入数据成功!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        break;
                    default:
                        status = messdisp(status);
                        break;
                }
            }
    
            private void button8_Click(object sender, EventArgs e)
            {
                textBox8.Text = "";
            }
    
            private void label24_Click(object sender, EventArgs e)
            {
    
            }
        }
    }
    

    展开全文
  • FM1208-CPU卡VB6示例源码.rar,FM1208-CPU卡VB6示例源码,Project1.exe,Project1.vbp,Module1.bas,Form1.frm,Project1.vbw,Form3.frm,请看说明,否则可能运行错误.txt,Form1.frx,OUR_MIFARE.dll,MSSCCPRJ.SCC,Form2....
  • Java读写CPU卡FM1208芯片

    2022-03-05 16:02:15
    Java 通过Jna调用DLL动态库函数读写FM1208 CPU卡,包括初始化CPU卡,创建文件、更改文件密码、读写文件等操作。

    发卡器 介绍:https://item.taobao.com/item.htm?spm=a1z10.5-c.w4002-17663462238.11.19b55f800Oz8WF&id=45006910325https://item.taobao.com/item.htm?spm=a1z10.5-c.w4002-17663462238.11.19b55f800Oz8WF&id=45006910325

    import com.sun.jna.Library ;
    import com.sun.jna.Native;
    import java.io.IOException;
    
    interface CLibrary extends Library {
        //DLL绝对路径的地址获取,注意要去空格,不要使用中文目录
        //不同版本的读写器,接口DLL文件名称、函数名称是一样的,但内核代码不一样,请选用与读写器、操作系统一致的OUR_MIFARE.dll
        String filePath = CLibrary.class.getResource("").getPath().replaceFirst("/","").replaceAll("%20"," ")+"OUR_MIFARE";
        CLibrary sdtapi = (CLibrary) Native.loadLibrary(filePath, CLibrary.class);
    
        //动态链接库中的方法
        byte pcdbeep(int xms);                         //让设备发出声音
        byte pcdgetdevicenumber(byte[] devicenumber);  //读取设备编号
        byte cpurequest(byte[] mypiccserial,byte[] myparam,byte[] myver,byte[] mycode);    //激活CPU卡
        byte cpursinit(byte emptycard, byte[] mypicckey, byte mykeylen, int spacesize);    //初始化CPU卡
        byte cpursfileadd(byte FileIndex,byte[] RFilekey,byte RKLen, byte[] WFilekey,byte WKLen,int FileSize);   //创建空文件
        byte cpursfilekeychg(byte FileIndex, byte ctrlCode,byte[] Autkey,byte AKLen,byte[] Newkey,byte NKLen);   //修改文件密码
        byte cpursfiledataread(byte FileIndex,byte ctrlCode,byte[] Autkey,byte AKLen,byte DataStart,byte[] DataBuf,byte DataLen);    //读CPU卡内文件信息
        byte cpursfiledatawrite(byte FileIndex,byte ctrlCode,byte[] Autkey,byte AKLen,byte DataStart,byte[] DataBuf,byte DataLen);   //写数据到文件内
        byte cpurscardkeychg(byte[] Oldkey,byte OKLen, byte[] Newkey,byte NKLen);  //修改CPU卡密码,卡密码与文件密码无关不影响数据安全
        byte cpurscardclr();  //强制清空已用cpursinit函数成功初始化过的卡
    }
    
    public class RWFm1208Cpu {
    
        public static void main(String[] args) throws Exception  {
            System.setProperty("jna.encoding", "GBK");
            String filePath = CLibrary.class.getResource("").getPath().replaceFirst("/", "").replaceAll("%20", " ") + "OUR_MIFARE.DLL";
            System.out.println("本示例引用的DLL文件:" + filePath);
    
            if (args.length == 0) {
                System.out.println("\n请先输入运行参数!");
                System.out.println("\n参数 0:驱动读卡器嘀一声");
                System.out.println("\n参数 1:读取设备编号");
                System.out.println("\n参数 2:激活CPU卡");
                System.out.println("\n参数 3:初始化CPU卡");
                System.out.println("\n参数 4:创建文件");
                System.out.println("\n参数 5:修改文件密码");
                System.out.println("\n参数 6:读CPU卡内文件信息");
                System.out.println("\n参数 7:写数据到文件内");
                System.out.println("\n参数 8:更改CPU卡认证密码");
                System.out.println("\n参数 9:强制清空已用cpursinit函数成功初始化过的卡");
                return;
            }
    
            //Java中只能使用string1.equals(string2)的方式来比较字符串
            if (args[0].equals("0")) {             //驱动读卡器发嘀一声
                System.out.print("\n0-驱动读卡器嘀一声\n");
                CLibrary.sdtapi.pcdbeep(50);
                System.out.print("结果:如果能听到读卡器嘀一声表示成功,否则请检查读卡器是否已连上线!\n");
    
            } else if (args[0].equals("1"))          //读取设备编号,可做为软件加密狗用,也可以根据此编号在公司网站上查询保修期限
            {
                int status;                          //存放返回值
                byte[] devicenumber = new byte[4];   //4字节设备编号
    
                status =(int)(CLibrary.sdtapi.pcdgetdevicenumber(devicenumber) & 0xff);//& 0xff用于转为无符号行数据
                System.out.print("\n1-读取设备编号\n");
                System.out.print("结果:");
                if (status == 0) {
                    CLibrary.sdtapi.pcdbeep(38);
                    System.out.print("读取成功!设备编号为:" + (devicenumber[0] & 0xff) + "-" + (devicenumber[1] & 0xff) + "-" + (devicenumber[2] & 0xff) + "-" + (devicenumber[3] & 0xff)+"\n");
                } else {
                    PrintErrInf(status);   //返回代码提示
                }
    
            }else if (args[0].equals("2"))          //激活CPU卡,每次卡离开过感应区都要先激活才能继续操作卡片
            {
                int status;                          //存放返回值
                byte[] mypiccserial = new byte[4];   //4字节设备编号
                byte[] myparam = new byte[4];        //4字节卡参数
                byte[] myver= new byte[1];
                byte[] mycode= new byte[1];
    
                System.out.print("\n2-激活CPU卡,每次卡离开过感应区都要先激活才能继续操作卡片\n");
                status =(int)(CLibrary.sdtapi.cpurequest(mypiccserial,myparam, myver, mycode) & 0xff);//& 0xff用于转为无符号行数据
                if (status == 0 || status == 52) {
                    CLibrary.sdtapi.pcdbeep(38);
                    String serialnumber = "";
                    for (int i = 0; i < 4; i++) {
                        String bytestr = "00" + Integer.toHexString(mypiccserial[i] & 0xff);
                        serialnumber = serialnumber + bytestr.substring(bytestr.length() - 2, bytestr.length());
                    }
                    System.out.print("CPU卡激活成功,卡号:" + serialnumber+"\n");
                } else {
                    PrintErrInf(status);   //返回代码提示
                }
    
            }else if (args[0].equals("3"))          //初始化CPU卡
            {
                int status;                          //存放返回值
                byte[] mypicckey = new byte[16];     //卡片认证密码,16进制,最好不要随便修改,此密码不影响数据安全
                byte mykeylen = 16 ;                 //卡片密码长度
                int  spacesize= 1000;                //应用空间字节大小(要大于所有文件总和),根据不同容量的卡设不同值
                byte emptycard=1;                    //初始化前是否清空卡内数据,取值1将先清空卡,取值为0不清空现有数据
    
                for(int i=0;i<16;i++){
                    mypicckey[i]=(byte) 0xff;
                }
                System.out.print("\n3-初始化CPU卡\n");
                status =(int)(CLibrary.sdtapi.cpursinit(emptycard, mypicckey, mykeylen, spacesize) & 0xff);//& 0xff用于转为无符号行数据
                if (status == 0 ) {
                    CLibrary.sdtapi.pcdbeep(38);
                    System.out.print("初始化卡成功!\n" );
                } else {
                    PrintErrInf(status);   //返回代码提示
                }
    
            }else if (args[0].equals("4"))           //创建文件
            {
                int status;                          //存放返回值
                byte RKLen = 16 ;                    //文件 只读权限密码 长度
                byte[] RFilekey = new byte[RKLen];   //文件 只读权限密码
                byte WKLen = 16 ;                    //文件 读写权限密码 长度
                byte[] WFilekey = new byte[WKLen];   //文件 读写权限密码,此权限高,可认证此密码修改只读密码,要记住文件密码
                byte FileIndex=0;                    //文件号,取值0 到 5
                int FileSize=300;                    //指定文件大小字节数
    
                for(int i=0;i<16;i++){
                    RFilekey[i]=(byte) 0xff;
                    WFilekey[i]=(byte) 0xff;
                }
    
                System.out.print("\n4-创建文件\n");
                status =(int)(CLibrary.sdtapi.cpursfileadd(FileIndex, RFilekey, RKLen, WFilekey, WKLen, FileSize) & 0xff);//& 0xff用于转为无符号行数据
                if (status == 0 ) {
                    CLibrary.sdtapi.pcdbeep(38);
                    System.out.print(Integer.toHexString(FileIndex)+" 号文件创建成功!\n" );
                } else {
                    PrintErrInf(status);   //返回代码提示
                }
    
            }else if (args[0].equals("5"))           //修改文件密码
            {
                int status;                          //存放返回值
                byte OldKey=0;                       //取值 0 表示用只读密码来认证,取值 2 表示用读写密码来认证
                byte AKLen = 16 ;                    //文件 认证密码 长度
                byte[] Autkey = new byte[AKLen];     //文件 认证密码
    
                byte ChaKey=0;                       //取值 0 表示更改只读密码,   取值 1 表示更改读写密码
                byte NKLen = 16 ;                    //文件 新密码密码 长度
                byte[] Newkey = new byte[NKLen];     //文件 新密码密码
                byte FileIndex=0;                    //文件号,取值0 到 5
                byte ctrlCode=(byte)(ChaKey+OldKey);
    
                for(int i=0;i<16;i++){               //文件认证密码、文件新密码,修改好要记住新密码,否则文件不能读写
                    Autkey[i]=(byte) 0xff;
                    Newkey[i]=(byte) 0xff;
                }
    
                System.out.print("\n5-修改文件密码\n");
                status =(int)(CLibrary.sdtapi.cpursfilekeychg(FileIndex, ctrlCode, Autkey, AKLen, Newkey, NKLen) & 0xff);//& 0xff用于转为无符号行数据
                if (status == 0 ) {
                    CLibrary.sdtapi.pcdbeep(38);
                    System.out.print(Integer.toHexString(FileIndex)+" 号文件密码修改成功!\n" );
                } else {
                    PrintErrInf(status);   //返回代码提示
                }
    
            }else if (args[0].equals("6"))           //读CPU卡内文件信息
            {
                int status;                          //存放返回值
                byte AKLen = 16 ;                    //文件 认证密码 长度
                byte[] Autkey = new byte[AKLen];     //文件 认证密码
                byte FileIndex=0;                    //文件号,取值0 到 5
                byte DataStart=0;                    //读起始位置
                byte DataLen = 50 ;                  //读长度最大不能超过255,如文件长度>255 要循环读取
                byte[] DataBuf = new byte[DataLen];  //读文件数据缓冲
                byte ctrlCode=2;                     //取值 0 表示用只读密码来认证,取值 2 表示用读写密码来认证
    
                for(int i=0;i<16;i++){               //文件认证密码
                    Autkey[i]=(byte) 0xff;
                }
    
                System.out.print("\n6-读CPU卡内文件信息\n");
                status = (int)(CLibrary.sdtapi.cpursfiledataread(FileIndex, ctrlCode, Autkey, AKLen, DataStart, DataBuf,DataLen) & 0xff);//& 0xff用于转为无符号行数据
                if (status == 0 ) {
                    CLibrary.sdtapi.pcdbeep(38);
                    String filedata="";
                    for (int i = 0; i < DataLen; i++) {
                        String bytestr = "00" + Integer.toHexString(DataBuf[i] & 0xff);
                        filedata = filedata + bytestr.substring(bytestr.length() - 2, bytestr.length()) +" ";
                    }
                    System.out.print(Integer.toHexString(FileIndex)+" 号文件读取数据:"+filedata+"\n" );
                } else {
                    PrintErrInf(status);   //返回代码提示
                }
    
            }else if (args[0].equals("7"))           //写数据到文件内
            {
                int status;                          //存放返回值
                byte AKLen = 16 ;                    //文件 认证密码 长度
                byte[] Autkey = new byte[AKLen];     //文件 认证密码
                byte FileIndex=0;                    //文件号,取值0 到 5
                byte DataStart=0;                    //写起始位置
                byte DataLen = 50 ;                  //写长度最大不能超过247,如文件长度>247 要循环写入
                byte[] DataBuf = new byte[DataLen];  //写文件数据缓冲
                byte ctrlCode=2;                     //取值 0 表示用只读密码来认证,取值 2 表示用读写密码来认证
    
                for(int i=0;i<16;i++){               //文件认证密码
                    Autkey[i]=(byte) 0xff;
                }
    
                //写中文或字母数字等字符信息,将要写入的字符转ASCII码写入
                String WriteStr = "伟大的中华人民共和国万岁!1949-10-01                                "; //将要写入的文字生成字节数组
                byte[] strbuf = WriteStr.getBytes("gb2312");
                for (int i = 0; i < DataLen; i++) {           //将要写的数据填入写卡缓冲
                    DataBuf[i] = strbuf[i];
                }
    
                System.out.print("\n7-写数据到文件内\n");
                status =(int)(CLibrary.sdtapi.cpursfiledatawrite(FileIndex, ctrlCode, Autkey, AKLen, DataStart, DataBuf,DataLen) & 0xff);//& 0xff用于转为无符号行数据
                if (status == 0 ) {
                    CLibrary.sdtapi.pcdbeep(38);
                    System.out.print(Integer.toHexString(FileIndex)+" 号文件写数据成功!\n" );
                } else {
                    PrintErrInf(status);   //返回代码提示
                }
    
            }else if (args[0].equals("8"))           //修改改卡片密码(一般无必要修改,卡密码与文件内数据无关)
            {
                int status;                          //存放返回值
                byte OKLen = 16;                     //卡 旧密码 长度
                byte[] Oldkey = new byte[OKLen];     //卡 旧密码
    
                byte NKLen = 16;                     //卡 新密码密码 长度
                byte[] Newkey = new byte[NKLen];     //卡 新密码密码
    
                for (int i = 0; i < 16; i++) {       //修改卡密码请记住
                    Oldkey[i] = (byte) 0xff;
                    Newkey[i] = (byte) 0xff;
                }
    
                System.out.print("\n8-修改CPU卡片密码\n");
                status =(int)(CLibrary.sdtapi.cpurscardkeychg(Oldkey, OKLen, Newkey, NKLen) & 0xff);//& 0xff用于转为无符号行数据
                if (status == 0 ) {
                    CLibrary.sdtapi.pcdbeep(38);
                    System.out.print("CPU卡修改卡片密码成功!\n");
                } else {
                    PrintErrInf(status);   //返回代码提示
                }
    
            }else if (args[0].equals("9")){    //强制清空已用cpursinit函数成功初始化过的卡
                int status=(int)(CLibrary.sdtapi.cpurscardclr() & 0xff);//& 0xff用于转为无符号行数据
                if (status == 0 ) {
                    CLibrary.sdtapi.pcdbeep(38);
                    System.out.print("\n强制清空卡成功!\n");
                } else if(status == 64){
                    System.out.print("此卡为未经过我们cpursinit函数成功初始化的卡!\n");
                }else{
                    PrintErrInf(status);   //返回代码提示
                }
            }
        }
    
        //----------------------------------------------------------------------------------返回代码提示
        static void PrintErrInf(int errcode) {
            switch(errcode){
                case 8:
                    System.out.print("错误代码:8,未寻到卡,请重新拿开卡后再放到感应区!\n");
                    break;
                case 21:
                    System.out.print("错误代码:21,没有动态库!\n");
                    break;
                case 22:
                    System.out.print("错误代码:22,动态库或驱动程序异常!\n");
                    break;
                case 23:
                    System.out.print("错误代码:23,驱动程序错误或尚未安装!\n");
                    break;
                case 24:
                    System.out.print("错误代码:24,操作超时,一般是动态库没有反映!\n");
                    break;
                case 25:
                    System.out.print("错误代码:25,发送字数不够!\n");
                    break;
                case 26:
                    System.out.print("错误代码:26,发送的CRC错!\n");
                    break;
                case 27:
                    System.out.print("错误代码:27,接收的字数不够!\n");
                    break;
                case 28:
                    System.out.print("错误代码:28,接收的CRC错!\n");
                    break;
                case 50:
                    System.out.print("错误代码:50,RATS错误,厂家调试代码,用户不需理会!\n");
                    break;
                case 51:
                    System.out.print("错误代码:51,PPS错误,厂家调试代码,用户不需理会!\n");
                    break;
                case 52:
                    System.out.print("错误代码:52,已进入了14443-4协议状态,可进行CPU卡功能所有操作了!\n");
                    break;
                case 53:
                    System.out.print("错误代码:53,CPU卡功能通讯错误,请先激活卡片!\n");
                    break;
                case 54:
                    System.out.print("错误代码:54,数据不足,需要接着发送未完成的数据至卡上!\n");
                    break;
                case 55:
                    System.out.print("错误代码:55,发送ACK指令给卡,让卡接着发送数据回来!\n");
                    break;
                case 56:
                    System.out.print("错误代码:56,清空根目录失败!\n");
                    break;
                case 57:
                    System.out.print("错误代码:57,卡片不支持功能!\n");
                    break;
                case 58:
                    System.out.print("错误代码:58,卡片初始化失败!\n");
                    break;
                case 59:
                    System.out.print("错误代码:59,分配的空间不足!\n");
                    break;
                case 60:
                    System.out.print("错误代码:60,本次操作的实体已存在!\n");
                    break;
                case 61:
                    System.out.print("错误代码:61,无足够空间!\n");
                    break;
                case 62:
                    System.out.print("错误代码:62,文件不存在!\n");
                    break;
                case 63:
                    System.out.print("错误代码:63,权限不足,有可能是用只读密码认证,导致无法更改读写密码或无法写文件!\n");
                    break;
                case 64:
                    System.out.print("错误代码:64,密码不存在,或密钥文件未创建!\n");
                    break;
                case 65:
                    System.out.print("错误代码:65,传送长度错误!\n");
                    break;
                case 66:
                    System.out.print("错误代码:66,Le错误,即接收的数据长度指定过大!\n");
                    break;
                case 67:
                    System.out.print("错误代码:67,功能不支持或卡中无MF 或卡片已锁定!\n");
                    break;
                case 68:
                    System.out.print("错误代码:68,密码认证错误次数过多,该密码已被锁死!\n");
                    break;
                case 70:
                case 71:
                case 72:
                case 73:
                case 74:
                case 75:
                case 76:
                case 77:
                case 78:
                case 79:
                case 80:
                case 81:
                case 82:
                case 83:
                case 84:
                case 85:
                    System.out.print("错误代码:"+Integer.toString(errcode)+",密码错误,剩余次数为"+Integer.toString(errcode-70)+",如果为0,该密码将锁死,无法再认证!\n");
                    break;
                case 86:
                    System.out.print("错误代码:"+Integer.toString(errcode)+",更改后的密码长度必须和创建时的长度一致!\n");
                    break;
                case 87:
                    System.out.print("错误代码:"+Integer.toString(errcode)+",应用目录不存在!\n");
                    break;
                case 88:
                    System.out.print("错误代码:"+Integer.toString(errcode)+",应用文件不存在!\n");
                    break;
                case 89:
                    System.out.print("错误代码:"+Integer.toString(errcode)+",文件号不能超过 5 \n");
                    break;
                case 90:
                    System.out.print("错误代码:"+Integer.toString(errcode)+",读取文件时返回的长度不足,数据可能不正确!\n");
                    break;
                case 91:
                    System.out.print("错误代码:"+Integer.toString(errcode)+",一次读文件的长度不能超过 255\n");
                    break;
                case 92:
                    System.out.print("错误代码:"+Integer.toString(errcode)+",一次写文件的长度不能超过 247\n");
                    break;
                default:
                    System.out.print("未知错误,错误代码:"+Integer.toString(errcode)+"\n");
                    break;
            }
        }
    
    }
    

    展开全文
  • APDU指令读写FM1208CPU 卡
  • //FM1208-43 CPU卡状态字定义 根据FMCOS通用技术手册_仅供参考_1.1_200907.pdf编制 // //当SW1的高半字节为’9’,且低半字节不为’0’时,其含义依赖于相关应用。 //当SW1的高半字节为’6’,且低...
  • PM3操作FM1208系列CPU卡.pdf
  • CPU卡FM1208操作

    千次阅读 2018-08-16 18:17:33
    参考https://blog.csdn.net/hongprovelllll/article/details/51354978建立... 赵同学整理版: /*********************************************************/ 复旦微建议门禁流程 选择主目录: ... 6F10840E3150415...
  • FM1208非接触CPU卡读写系统的研制.pdf
  • 本文将重点介绍PLC机台操作权限控制读卡器|读写器T6-AS-00-01读写FM1208芯片CPU卡操作步骤与方法。 1. 先连接设备。 2. 空白卡中存在一个主应用目录,里面是空的,就相当于一个空文件夹。 我们可以直接在 这个...
  • 本文仅记录简单的发卡流程,具体意义请参考相关文档 以下是针对一张新卡而言,如果是旧卡密钥可能就不是FFFFFFFFFFFFFFFF 1、获取随机数(先复位) 0084000004 2、外部认证:  获取随机数: ...
  • FM1208-CPU卡易写版C#示例源码.rar,FM1208-CPU卡易写版C#示例源码,Form1.Designer.cs,Program.cs,app.config,Form2.Designer.cs,Form2.resx,重要说明.txt,obj,x86,Release,C井源代码CPU卡操作.exe,C井源代码CPU卡...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 381
精华内容 152
关键字:

FM1208