CPU卡基本指令
复旦1208出厂初始主控密钥为8个字节的FF, 即为 FFFFFFFFFFFFFFFF。 执行指令时返回9000表示成功
操作指令
1.选择MF下的根目录
- 执行命令: 00A4000000
- 返回值为6F15840E315041592E5359532E4444463031A5038801019000具体意思查复旦微电子CPU卡COSFMCOS 2_0用户手册
2.外部认证
-
执行指令: 0084000004 取4个字节的随机数
-
用8个字节的初始密钥FFFFFFFFFFFFFFFF和4随机数+00000000进 行解密生成8字节解密数据(用DES函数计算得出, DES函数文末会给出)
-
发送0082000008+8字节密文数据
3.删除MF下所有文件指令
- 执行指令: 800E000000
- 返回 01 由于擦除命令时间较长需等待, 当返回9000后,表示擦除成功
4.建立MF目录下的密钥文件
- 先选择根目录: 00A4000000
- 然后执行建密钥文件命令:80E0 0000 07 3F 00B0 01F0 FFFF
指令 | 说明 |
---|---|
80E0 | 指令类别和指令码 |
0000 | 文件标识 |
07 | 长度 |
3F | 文件类型, 为密钥文件 |
00B0 | 所建文件可用的空间,即可用0XB0个字节的空间 |
01F0 | 01:读权限, F0:写权限 |
5.密钥文件建好后增加密钥
执行指令: 80D4 0100 0D 39 F0F0 AA55 FFFFFFFFFFFFFFFF
指令 | 说明 |
---|---|
80D4 | 指令类别和指令码 |
0100 | 文件标识 |
0D | 长度 |
39 | 文件类型,此为外部认证密钥 |
F0 | 读权限 |
F0 | 写权限 |
AA | 后续状态 |
55 | 错误计数,当前为5次机会,返回错 误代码是63CX, X就是次数了,当X为0时卡永久补锁 |
6.建立目录文件DF
执行指令: 80E0 3F01 0D 38 0520 F0F0 95 FFFF 4444463031
指令 | 说明 |
---|---|
80E0 | 指令类别和指令码 |
3F01 | 文件标识 |
0D | 长度 |
38 | 文件类型 |
0520 | 文件的空间大小 |
F0F0 | F0:读权限,F0:写权限 |
95 | |
FFFF | |
4444463031 | 文件名DDF01也就是ASCII码了 |
7.建立DF目录下密钥文件
执行指令: 80E0 0001 07 3F 018F 95F0 FFFF
8.在DF目录下密钥文件里增加口令密钥
执行指令: 80D4 0101 08 3A F0EF 44 55 123456
指令 | 说明 |
---|---|
80D4 | 指令类别和指令码 |
0101 | 文件标识 |
08 | 长度 |
3A | 文件类型,即口令密钥 |
F0EF | F0:读权限,EF:写权限 |
44 | 后续状态 |
55 | 错误计数 |
123456 | 3个字节的PIN密码 |
9.基本文件,建立二进制文件
1.执行指令: 80E0 0003 07 28 001E F0F0 FF02
指令 | 说明 |
---|---|
80E0 | 指令类别和指令码 |
0003 | 文件标识 |
07 | 长度 |
28 | 文件类型,即口令密钥 |
001E | 空间大小,即为写入二进制文件的字节个数 |
F0F0 | F0:读权限;F0:写权限 |
FF02 |
- 执行指令: 80E0 0004 07 28 000F F4F0 FF02
指令 | 说明 |
---|---|
80E0 | 指令类别和指令码 |
0004 | 文件标识 |
07 | 长度 |
28 | 文件类型,即口令密钥 |
000F | 空间大小,即为写入二进制文件的字节个数 |
F4F0 | F4:读权限;F0:写权限 |
FF02 |
10. 写二进制文件,须先读出该文件所在目录下的标识,然后再给其写入
- 执行指令:比如读取标识为0003的,则:00A4000002 0003, 返回9000表示读取成功
- 然后写入你要写入内容,空间大小不能超过1E字节(建立该文件时设定的)
- 执行写二进制的指令: 00D6 0000 05 0102030405
指令 | 说明 |
---|---|
00D6 | 指令类别和指令码 |
0000 | 偏移量,意思是指要读出的内容从该位置开始 |
05 | 长度LEN |
0102030405 | 要写入的内容与前面的长度对应 |
11. 读出二进制文件
- 执行指令:比如读取标识为0003的,则:00A4000002 0003, 返回9000表示读取成功
- 执行指令: 00B0 0000 0000
指令 | 说明 |
---|---|
00B0 | 指令类别和指令码 |
0000 | 偏移量 |
0000 | 不在线路保护下该两个字节为 无效,写0即可 |
12. 验证口令
在当前目录下执行指令: 0020 0001 03 123456
指令 | 说明 |
---|---|
0020 | 指令类别和指令码 |
0001 | 标识 |
03 | 为密码个数字节为单位 |
123456 | 密码(PIN上面已设为123456) |
注意事项
- 关于对文件的访问必须在当前目录下才能访问,否则提示错误码:6A82找不到该文件
- 在当前目录下读写该文件时,如果设置有权限时,必须要通过口令或外部认证方可读写,否则提示:安全状态不满足
- 操作密码时一定要注意,记得自己所设的密码, 63CX,这里的X就是还剩可用多少次了
附录
DES算法(java)
DES算法
//DES算法
public static byte[] desCrypto(byte[] datasource, byte[] password) {
try{
SecureRandom random = new SecureRandom();
DESKeySpec desKey = new DESKeySpec(password);
//创建一个密匙工厂,然后用它把DESKeySpec转换成
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey securekey = keyFactory.generateSecret(desKey);
//Cipher对象实际完成加密操作
Cipher cipher = Cipher.getInstance("DES");
//用密匙初始化Cipher对象
cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
//现在,获取数据并加密
//正式执行加密操作
return cipher.doFinal(datasource);
}catch(Throwable e){
e.printStackTrace();
}
return null;
}
十六进制与字符串转换
private static final char[] HEX_CHAR = {'0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
/**
* byte[] to hex string
*
* @param bytes
* @return
*/
public static String bytesToHexFun1(byte[] bytes) {
// 一个byte为8位,可用两个十六进制位标识
char[] buf = new char[bytes.length * 2];
int a = 0;
int index = 0;
for(byte b : bytes) { // 使用除与取余进行转换
if(b < 0) {
a = 256 + b;
} else {
a = b;
}
buf[index++] = HEX_CHAR[a / 16];
buf[index++] = HEX_CHAR[a % 16];
}
return new String(buf);
}
/**
* 将16进制字符串转换为byte[]
*
* @param str
* @return
*/
public static byte[] toBytes(String str) {
if(str == null || str.trim().equals("")) {
return new byte[0];
}
byte[] bytes = new byte[str.length() / 2];
for(int i = 0; i < str.length() / 2; i++) {
String subStr = str.substring(i * 2, i * 2 + 2);
bytes[i] = (byte) Integer.parseInt(subStr, 16);
}
return bytes;
}
调用方法
public static void main(String[] args) {
byte[] key = DesUtils.toBytes("FFFFFFFFFFFFFFFF");
byte[] b = DesUtils.toBytes("496E75C300000000");
byte[] bytes1 = DesUtils.desCrypto(b, key);
String s = DesUtils.bytesToHexFun1(bytes1);
s = s.substring(0, s.length() /2);
System.out.printf("0082000008" + s);
}