软件世界网 购物 网址 三丰软件 | 小说 美女秀 图库大全 游戏 笑话 | 下载 开发知识库 新闻 开发 图片素材
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
移动开发 架构设计 编程语言 Web前端 互联网
开发杂谈 系统运维 研发管理 数据库 云计算 Android开发资料
  软件世界网 -> 研发管理 -> 文件系统创建—JavaCard开发第二篇 -> 正文阅读

[研发管理]文件系统创建—JavaCard开发第二篇


首先要知道Java card里面的文件系统结构,也就是有哪些文件:
[img]http://img.blog.csdn.net/20160402122723562?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
[img]http://img.blog.csdn.net/20160402122814625?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
[img]http://img.blog.csdn.net/20160402122833172?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
[img]http://img.blog.csdn.net/20160402122611390?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
包括四大类文件,应用基本文件——也就是发卡方官方的一些信息,然后是持卡人个人信息的文件,再就是EP(电子钱包)文件,以及最重要的密钥文件。并且密钥文件必须先于其他三个文件之前创建,因为没密码你弄啥操作不科学呀。
几大文件反应到代码中就是几大数据结构:
[img]http://img.blog.csdn.net/20160402133420996?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
理解了文件系统之后就要一一去看各个文件代码模块是怎么实现的:
举个例子:
[img]http://img.blog.csdn.net/20160402133818841?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
这是二进制文件数据结构的部分代码,可以看到它的构造函数需要传进一个pdata参数,其实就是要传输apdu命令的data部分给它。由于这几大数据结构代码课上都给得差不多了,而且本篇只讲文件系统的创建,所以目前只需要知道这几大文件数据结构的接口就够了,主要还是看主程序代码,也就是purse.java。嗯,本次java card的开发就是以电子钱包的开发作为项目来学习的。
先直接上主程序purse.java的代码,其他几个java文件的代码在后面学习篇再放:
//主文件:电子钱包,调用了其他几个辅助类。
//注意这些所有的代码和应用都是运行在卡片中的!
//而终端只是在命令行敲几句命令发送的那里.
package purse;

//import Purse;
import javacard.framework.APDU;
import javacard.framework.Applet;
import javacard.framework.ISO7816;
import javacard.framework.ISOException;
import javacard.framework.Util;

public class Purse extends Applet {
	//APDU Object
	private Papdu papdu;
	
	//文件系统,每次run的时候都相当于一张空白卡片,全部需要重新建立,
	//并且建立之后就归当前run的applet所有,某个文件可以随时被调用(keyfile)
	private KeyFile keyfile;            //密钥文件
	private BinaryFile cardfile;       //应用基本文件
	private BinaryFile personfile;     //持卡人基本文件
	private EPFile EPfile;              //电子钱包文件 Electronic Purse
	
	public Purse(byte[] bArray, short bOffset, byte bLength){
		papdu = new Papdu();
		
		byte aidLen = bArray[bOffset];
		if(aidLen == (byte)0x00)
			register();
		else
			register(bArray, (short)(bOffset + 1), aidLen);//注册applet
	}
	//安装applet
	public static void install(byte[] bArray, short bOffset, byte bLength) {
		new Purse(bArray, bOffset, bLength);
	}
	//执行applet
	public void process(APDU apdu) {
		if (selectingApplet()) {
			return;
		}		
		//步骤1:取APDU缓冲区数组引用并将之赋给新建数组
		byte buffer[] = apdu.getBuffer();
		//步骤2:取APDU缓冲区中数据放到变量papdu
		short lc = apdu.setIncomingAndReceive();//将apdu读取到卡片缓冲区当中并返回data段的长度
		papdu.cla = buffer[ISO7816.OFFSET_CLA];
		papdu.ins = buffer[ISO7816.OFFSET_INS];
		papdu.p1 = buffer[ISO7816.OFFSET_P1];
		papdu.p2 = buffer[ISO7816.OFFSET_P2];
		Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, papdu.pdata, (short)0, lc);
		//步骤3:判断命令APDU是否包含数据段,有数据则获取数据长度,并对le赋值,
		 //否则,即不需要lc和data,则获取缓冲区原本lc实际上是le
		 	//获取le的方法,因为不确定papdu有le部分,所以IOS7816下标可选项并没有le而是放在数据块中的.
		 	//如果有数据快,那le就是buffer[ISO7816.OFFSET_CDATA+lc]
		if(papdu.pdata.length != 0)
		{
			papdu.le = buffer[ISO7816.OFFSET_CDATA+lc];
			papdu.lc = buffer[ISO7816.OFFSET_LC];
		}
		else
			papdu.le = buffer[ISO7816.OFFSET_LC];//若没data部分则lc部分实际是le
		boolean rc = handleEvent();
		//步骤4:判断是否需要返回数据,并设置apdu缓冲区	
		if(papdu.le != 0)
		{
			Util.arrayCopyNonAtomic(papdu.pdata, (short)0, buffer, ISO7816.OFFSET_CDATA, (short)papdu.pdata.length);
			apdu.setOutgoingAndSend((short)5, (short)papdu.pdata.length);//把缓冲区的数据返回给终端			
		}
	}

	/*
	 * 功能:对命令的分析和处理
	 * 参数:无
	 * 返回:是否成功处理了命令
	 */
	private boolean handleEvent(){
		switch(papdu.ins){
			case condef.INS_CREATE_FILE:       	return create_file();
			//todo:完成写二进制命令,读二进制命令,写密钥命令
			case condef.INS_WRITE_KEY:			return write_key();
			case condef.INS_WRITE_BIN:			return write_bin();
			case condef.INS_READ_BIN:			return read_bin();
			case condef.INS_NIIT_TRANS:
				if(papdu.p1 == (byte)0x00)		return init_load();
				if(papdu.p1 == (byte)0x01)		return init_purchase();
				ISOException.throwIt(ISO7816.SW_WRONG_P1P2);//else抛出异常
			case condef.INS_LOAD:				return load();
		}	
		ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
		return false;
	}
	/*
	 * 功能:创建文件
	 */
	private boolean create_file() {
		switch(papdu.pdata[0]){ //data的第一位表示要创建文件的类型            
		case condef.EP_FILE:        return EP_file();  
		//todo:完成创建密钥文件,持卡人基本文件和应用基本文件
		case condef.KEY_FILE:		return Key_file();
		case condef.CARD_FILE:		return Card_file();
		case condef.PERSON_FILE:	return Person_file();
		default: 
			ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
		}
		return true;
	}
	/*
	 * 功能:创建电子钱包文件
	 */
	private boolean EP_file() {
		if(papdu.cla != (byte)0x80)
			ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
		
		if(papdu.lc != (byte)0x07)
			ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
		
		if(EPfile != null)//有文件了还重复创建则会报错
			ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
		
		if(keyfile == null)//都还没密钥文件(必须先于任何其他文件创建)
			ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
		
		EPfile = new EPFile(keyfile);
		
		return true;
	}
	//创建密钥文件
	private boolean Key_file()
	{
		if(papdu.cla != (byte)0x80)
			ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
		
		if(papdu.lc != (byte)0x07)
			ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
		
		if(keyfile != null)//有文件了还重复创建则会报错
			ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
		
		keyfile = new KeyFile();
		
		return true;
	}
	//创建应用基本文件
	private boolean Card_file()
	{
		if(papdu.cla != (byte)0x80)
			ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
		
		if(papdu.lc != (byte)0x07)
			ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
		
		if(cardfile != null)//有文件了还重复创建则会报错
			ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
		if(keyfile == null)//都还没密钥文件(必须先于任何其他文件创建)
			ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
		
		cardfile = new BinaryFile(papdu.pdata);//传进的参数就是要写入的内容
		
		return true;
	}
	//创建持卡人信息文件
	private boolean Person_file()
	{
		if(papdu.cla != (byte)0x80)
			ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
		
		if(papdu.lc != (byte)0x07)
			ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
		
		if(personfile != null)//有文件了还重复创建则会报错
			ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
		if(keyfile == null)//都还没密钥文件(必须先于任何其他文件创建)
			ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
		
		personfile = new BinaryFile(papdu.pdata);//传进的参数就是要写入的内容
		
		return true;
	}
	//写入各种密钥
	private boolean write_key()
	{
		return true;
	}
	//写入二进制文件
	private boolean write_bin()
	{
		return true;
	}
	//读取二进制文件
	private boolean read_bin()
	{
		return true;
	}
	/*
	 * 功能:圈存命令的实现
	 */
	private boolean load() {
		short rc;
		
		if(papdu.cla != (byte)0x80)
			ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
		
		if(papdu.p1 != (byte)0x00 && papdu.p2 != (byte)0x00)
			ISOException.throwIt(ISO7816.SW_WRONG_P1P2);
		
		if(EPfile == null)
			ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND);
		
		if(papdu.lc != (short)0x0B)
			ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
		
		rc = EPfile.load(papdu.pdata);
		
		if(rc == 1)
			ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
		else if(rc == 2)
			ISOException.throwIt(condef.SW_LOAD_FULL);
		else if(rc == 3)
			ISOException.throwIt(ISO7816.SW_RECORD_NOT_FOUND);
		
		papdu.le = (short)4;
		
		return true;
	}

	/*
	 * 功能:圈存初始化命令的实现
	 */
	private boolean init_load() {
		short num,rc;
		
		if(papdu.cla != (byte)0x80)
			ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
		
		if(papdu.p1 != (byte)0x00 && papdu.p2 != (byte)0x02)
			ISOException.throwIt(ISO7816.SW_WRONG_P1P2);
		
		if(papdu.lc != (short)0x0B)
			ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
		
		if(EPfile == null)
			ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND);
		
		num = keyfile.findkey(papdu.pdata[0]);
		
		if(num == 0x00)
			ISOException.throwIt(ISO7816.SW_RECORD_NOT_FOUND);
		
		rc = EPfile.init4load(num, papdu.pdata);
		
		if(rc == 2)
			ISOException.throwIt((condef.SW_LOAD_FULL));
		
		papdu.le = (short)0x10;
		
		return true;
	}
	
	/*
	 * 功能:消费命令的实现
	 */
	private boolean purchase(){
		return true;
	}
	/*
	 * 功能:余额查询功能的实现
	 */
	private boolean get_balance(){
		return true;
	}
	
	/*
	 * 功能:消费初始化的实现
	 */
	private boolean init_purchase(){
		return true;
	}
}

既然是要创建文件,当然就要先从终端获取apdu命令,判断它的命令里面是不是要卡片创建文件,怎么判断呢?通过ins值,就是这句代码:
case condef.INS_CREATE_FILE:       	return create_file();

这里有个常量,在condef.java中定义:
//这个文件表示的是一些常量
package purse;
/**
 * 已给出部分常数值,其他根据需要自行添加 
 */
//存储INS值文件,ins值表示命令的具体意思
public class condef {
	//----------------- INS Byte -------------------
	final static byte INS_CREATE_FILE     = (byte)0xE0;         //文件建立命令的INS值
	final static byte INS_WRITE_KEY       = (byte)0xD4;         //写入密钥命令的INS值
	final static byte INS_WRITE_BIN       = (byte)0xD6;         //写入二进制命令的INS值
	final static byte INS_READ_BIN        = (byte)0xB0;         //读取二进制文件的INS值
	final static byte INS_NIIT_TRANS      = (byte)0x50;         //初始化圈存和初始化消费命令的INS值
	final static byte INS_LOAD            = (byte)0x52;         //圈存命令的INS值
	
	//-------------- FILE TYPE Byte ---------------
	final static byte KEY_FILE            = (byte)0x3F;         //密钥文件的文件类型
	final static byte CARD_FILE           = (byte)0x38;         //应用基本文件的文件类型
	final static byte PERSON_FILE         = (byte)0x39;         //持卡人基本文件 的文件类型
	final static byte EP_FILE             = (byte)0x2F;         //电子钱包文件的文件类型
	
	//------------------------ SW --------------------- 
	final static short SW_LOAD_FULL = (short)0x9501;      //圈存超额	
}

condef.java文件里面定义了一些ins值常量,还有就是如果是要创建文件,那要创建的是什么文件呢,通过pdata的第一位判断,也就是pdata[0]:
[img]http://img.blog.csdn.net/20160402135106158?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
所以condef.java里面也定义了这部分文件类型的常量。
既然已经判断出了apdu命令是要我们创建文件,同时又判断出了要创建的是什么文件,接下来就简单了,就是直接调用几大文件数据结构的接口去创建相应的文件,同时,这里要判断一些异常的情况,也就是apdu命令有输入错误的情况,然后返回相应的异常给终端。比如:
		if(papdu.cla != (byte)0x80)
			ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
		
		if(papdu.lc != (byte)0x07)
			ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
		
		if(EPfile != null)//有文件了还重复创建则会报错
			ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
		
		if(keyfile == null)//都还没密钥文件(必须先于任何其他文件创建)
			ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);

嗯,创建文件就是这么简单了,主要就是要理解文件系统里面的几大文件,同时看懂文件数据结构的几个java文件是怎么实现的。然后调用就很简单了。
最后,看看运行结果,由于终端要发送不少命令,所以可以把命令全部放到文件里面,然后直接在命令行中读取文件,然后就会在模拟器中执行文件里面的所有命令了。
首先,把命令脚本名称改一下,主要是改后缀名为jcsh:
[img]http://img.blog.csdn.net/20160402135819708?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
然后运行之后再命令行中先输入:
/set-var path "文件路径(不包括文件名.jcsh)"

查找文件路径的快速方法(通用电脑小常识),查询文件属性,然后就可以看到文件所在的路径了。
输入上面那条路径命令之后,就再输入文件名(不包括后缀),比如这里是purse,然后回车就可以让模拟器执行命令脚本里面的所有命令了,注意,有时候脚本文件里面会有一些奇奇怪怪的未注释的中文字符,比如中文的空格,有很多软件开发工具都对这些非常敏感会导致执行脚本出错,我在执行脚本的时候就遇到了,解决办法是重新建一个txt文件,然后改下文件名,把脚本命令复制进来。
命令脚本内容:
[img]http://img.blog.csdn.net/20160402140411023?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
运行结果:
[img]http://img.blog.csdn.net/20160402140232131?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
可以看到都是No Error.也就把四大文件都给建立好了,后面的就是在文件里面进行添加密钥等等的操作了,这是后面学习篇的内容。值得注意的是,每次重新运行的时候,模拟器不会保存你之前创建的文件,毕竟只是个模拟器嘛。所以除非一直运行着保留着上面创建文件的状态,否则重新运行后应当重新建立文件。
......显示全文...
    点击查看全文


上一篇文章      下一篇文章      查看所有文章
2016-04-02 21:01:17  
研发管理 最新文章
拉格朗日乘数
maven之可视化项目依赖(Visualizingdepend
mac效率工具
Atitit.css规范bem项目中CSS的组织和管理
git入门
Asimplemodelfordescribingbasicsourcesofp
Linux进程管理浅析
我的openwrt学习笔记(十九):linux便捷开
2、微控制器选择
Git使用手册:为Git仓库创建Submodule
360图书馆 软件开发资料 文字转语音 购物精选 软件下载 美食菜谱 新闻资讯 电影视频 小游戏 Chinese Culture 股票 租车
生肖星座 三丰软件 视频 开发 短信 中国文化 网文精选 搜图网 美图 阅读网 多播 租车 短信 看图 日历 万年历 2018年1日历
2018-1-16 17:30:52
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  软件世界网 --