关于FM1208之类的CPU卡的总结说明

1、FMCOS的文件结构:

FMCOS IC卡的基本文件系统是由主文件 MF (Master File)、 目录文件 DF (Directory File) 和基本文件 EF(Element File)组成。主文件 MF 在 IC 卡中唯一存在,在 MF 下可以有多个 目录文件 DF 和基本文件 EF,每一个 MF 目录下的 DF 可以存放多个基本文件 EF 和多个下 级目录文件 DF,在这里我们称包含下级目录的目录文件为 DDF,不含下级目录的目录文件 为 ADF


1.1 MF文件
在 FMCOS 卡中,MF 文件唯一存在,是卡片文件系统的根。它相当于 DOS 的根目录。IC 卡复位后,卡片自动选择 MF 文件为当前文件,除了MF之外,其他的操作都必须先选择当前目录才能进行,只有MF目录是自动选择的。


1.2  DF文件

目录文件 DF 相当于 DOS 的目录,每个 DDF 下可建立一个目录文件,但不是强制的。任何一个 DF 在物理上和逻辑上都保持独立,都有自己的安全机制和应用数据,可以通过应用选择实现对其逻辑结构的访问。

1.3 EF文件


3.3. 文件访问方式





2、FMCOS命令

2.1  外部认证:这里值得注意的是出厂默认的CPU卡,取随机数的时候取8字节的随机数,然后用默认的16字节0xFF的数据进行3DES加密,加密后的8字节数据通过FMCOS的外部认证指令发送过去,认证成功返回9000.

2.2  在外部认证成功后,一开始情况下需要擦除整个MF文件系统,然后首先第一步需要建立自己的秘钥文件,包括外部认证秘钥、内部认证秘钥、口令秘钥等自己需要的秘钥文件,然后再建立自己的DF文件或者EF文件,进行读写操作。

3、利用PN532芯片进行开发步骤

一、首先对于PN532来说,在第一次操作前需要进行唤醒操作

二、需要进行 InListPassiveTarget操作操作成功后会选定卡片自动进入CPU操作层

三、对于CPU卡来说,所有的操作PN532都是通过 InDataExchange这条指令来进行,所以需要认真阅读本条指令的含义,举个例子,对于获取随机数来说,需要发送的指令是00 00 FF 08 F8 D4 40 01 00 84 00 00 08 5F 00,这里的D4 40是InDataExchange命令,01是指所选的卡片数量,然后后面的00 84 00 00 08是FMCOS手册取随机数的指令,5F是校验码,如果操作成功,返回00 00 FF 00 FF 00 00 00 FF 0D F3 D5 41 00 E0 FB AE 57 A9 4B B5 24 90 00 AD 00,这里可以看到返回的随机数是E0 FB AE 57 A9 4B B5 24,这样OK之后,其他的指令都可以通过这种方式来操作

以下是一个简单的使用C语言编写的FM1208 CPU的代码示例,其中使用了串口通信和APDU指令: ```c #include <stdio.h> #include <string.h> #include <stdlib.h> #include <termios.h> #include <fcntl.h> #include <unistd.h> #define MAX_BUF_LEN 1024 int serialOpen(char *port, int baudrate) { int fd; struct termios newtio; fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY); if (fd < 0) { perror("open"); return -1; } tcgetattr(fd, &newtio); memset(&newtio, 0, sizeof(newtio)); newtio.c_cflag = baudrate | CS8 | CLOCAL | CREAD; newtio.c_iflag = IGNPAR; newtio.c_oflag = 0; newtio.c_lflag = 0; newtio.c_cc[VTIME] = 0; newtio.c_cc[VMIN] = 1; tcflush(fd, TCIFLUSH); tcsetattr(fd, TCSANOW, &newtio); return fd; } void serialClose(int fd) { close(fd); } int sendAPDU(int fd, unsigned char *apdu, int apduLen, unsigned char *respBuf, int *respLen) { unsigned char buf[MAX_BUF_LEN]; int len; write(fd, apdu, apduLen); len = read(fd, buf, MAX_BUF_LEN); memcpy(respBuf, buf, len); *respLen = len; return 0; } int main(int argc, char **argv) { int fd; unsigned char apdu[256] = {0}; unsigned char respBuf[MAX_BUF_LEN] = {0}; int respLen = 0; // 打开串口 fd = serialOpen("/dev/ttyS0", B9600); if (fd < 0) { printf("open serial port failed\n"); return -1; } // 发送APDU指令 // 发 apdu[0] = 0x00; apdu[1] = 0xA4; apdu[2] = 0x04; apdu[3] = 0x00; apdu[4] = 0x08; apdu[5] = 0xA0; apdu[6] = 0x00; apdu[7] = 0x00; apdu[8] = 0x00; apdu[9] = 0x03; apdu[10] = 0xF0; apdu[11] = 0x01; apdu[12] = 0x01; apdu[13] = 0x05; sendAPDU(fd, apdu, 14, respBuf, &respLen); memset(apdu, 0, sizeof(apdu)); memset(respBuf, 0, sizeof(respBuf)); respLen = 0; // apdu[0] = 0x00; apdu[1] = 0xB0; apdu[2] = 0x00; apdu[3] = 0x00; apdu[4] = 0x08; sendAPDU(fd, apdu, 5, respBuf, &respLen); // 处理片响应 if (respBuf[respLen - 2] == 0x90 && respBuf[respLen - 1] == 0x00) { printf("Read card success\n"); } else { printf("Read card failed\n"); } // 关闭串口 serialClose(fd); return 0; } ``` 需要注意的是,上述代码仅供参考,具体的代码实现需要根据所使用的硬件平台和应用场景进行相应的调整和修改。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值