Java卡

JAVACARD开发基础规则

2020-06-28 15:11:35 共鸣 73

参考Java Card & STK Applet Development Guidelines文档。

  遵从以下规则能够让你的程序更加标准化和减少出现问题的可能性。

  1.尽可能使用API,而不是造轮子。

  使用API可以减少重复代码,而且API可以提供的强大功能。

  2.为了确保卡的安全性,PIN码以及秘钥不能存储在基本数组中。可以采取以下方法存储。


OwnerPIN pin; 
Pin = new OwnerPIN (tryLimitApplet, maxPINSizeApplet); 
Pin.update( pinApplet offset, length ) 
Key rsaPrivateKey; 
rsaPrivateKey = (RSAPPrivateKey) KeyBuilder.buildKey 
(KeyBuilder.TYPE_RSA_PRIVATE, KeyBuilder.LENGTH_RSA_512, False); 
rsaPrivateKey.setExponent(bufferExp, offsetExp, lengthExp); 
rsaPrivateKey.setModulus(bufferMod, offsetMod, lengthMod);

  3.敏感的数据应该在会话开始初始化,会话结束后清除,(该规则适用于全局数组,秘钥更新和会话对象)。

  注意:要重置一个key,需要使用clear()方法,而不是使用0或者其他值覆盖。因为使用clear()方法,秘钥的初始化状态重置为false。


sessionflags = JCSystem.makeTransientByteArray ((short)13,JCSystem.CLEAR_ON_RESET); 
sessionflags = JCSystem.makeTransientByteArray ((short)13,JCSystem.CLEAR_ON_DESELECT);
sessionKey = (DESKey)KeyBuilder.buildKey(KeyBuilder.TYPE_DES_TRANSIENT_RESET,KeyBuilder.LENGTH_DES3_2KEY, 
false); 
sessionKey = (DESKey)KeyBuilder.buildKey(KeyBuilder.TYPE_DES_TRANSIENT_DESELECT,KeyBuilder.LENGTH_DES3_2KEY, 
false);

   蓝色的代码表示数据会在卡复位的时候清除,即卡断电或者重启的时候。而红色的代码表示数据会在该应用断开选择的时候清除数据。

  4.敏感的数据应该存储在临时数据类型中,并且避免存储在APDU的buffer中。  

sessionflags = 
JCSystem.makeTransientByteArray
((short)13,JCSystem.CLEAR_ON_DESELECT);

  5.保护你的敏感数据,防止回滚攻击(Rollback attack)

  回滚(Rollback)指的是程序或数据处理错误,将程序或数据恢复到上一次正确状态的行为。回滚包括程序回滚和数据回滚等类型。

  当你的代码正在处于transaction(事务,程序执行单元)中突然断电,卡状态将会回滚到旧值,攻击者可以利用这点进行攻击。当处理敏感数据的时候,一定要引入计数管理器,以应对处理敏感数据时的回滚攻击。

规则:假如预防机制需要依靠计数器的话,并且该机制需要被管理,需要按照以下行为进行执行。

  (1)检查计数器的值,如果被置为0的话,返回错误;

  (2)原子操作(不可打断)递减计数器的值;

  (3)验证这个代码不处于transaction(事务,程序执行单元);

  (4)运行“try”函数;

  (5)假如“try”运行成功,原子操作增加计数器的值。

  6.所有初始化的buffer,一定要定义为静态数据。

  初始化数组定义为静态数据有以下好处:

  (1)节省执行时间,在初始化的过程中;

  (2)节省代码空间;

  (3)在初始化的过程中防止错误(transction 缓存满了)。

  7.全局变量和局部变量

  在javacard应用程序中有许多变量:实例变量(全局变量),在对象初始化的时候创建;局部变量,他只能在申明他们的函数或者快中使用。

一些基本的规则:

  (1)当能够使用静态变量的时候,尽量不要使用全局变量。他可以减少类实例的冗余。

  (2)尽量少使用全局变量。

  (3)不可变的常量必须申明为static final。

  (4)不要申明太多参数,在一个方法中。非常消耗内存(RAM)。

  (5)局部变量的访问速度比全局变量快:

     Working variables(像循环计数器,临时存储变量),一定要在方法中申明为局部变量而不是类中的全局变量,这样可以防止超过NVM的容量;

     Working buffers应该尽可能申明为transient 数组(可以锁定在RAM区域),这样可以避免超过NVM容量限制。假如缺少RAM资源,一定要注意 Working buffers的更新频率(更新时间点以及更新次数)。

    RAM空间应该需要时才使用,因为RAM是一个稀缺资源。

  (6)方法参数分解,使用全局变量代替参数,并且传递一个对象而不是一个参数列表。

  (7)最大化局部变量使用效率,尽量复用局部变量;

  尽量减少类和对象的数量以及大小,可以有助于解决bug,增强程序可读性。

  (8)禁止存储临时入口对象的引用。

    在javacard标准中指定了一些JCRE的entry point objects(EPO)入口对象。在这些EPOS中,这些临时的EPO是禁止存储在类变量、全局变量或则数组阵列中。JCRE检测和禁止将这些对象的引用存储在程序中,作为应用防火墙的一部分。如果这么做的话系统会抛出安全异常。

    一些主要的临时EPO:APDU, EnvelopeHandler, ProactiveHandler, EnvelopeResponseHandler, ProactiveResponseHandler 。

    红色标注的代码有问题,因为它使用全局变量来存储EPO。


public class exampleD8 extends Applet implements
ToolkitInterface {
byte[] apduBuffer;
byte[] envHandler;
void process(APDU apdu){
byte[] buffer;
apduBuffer = apdu.getBuffer();
buffer = apdu.getBuffer();
}
void processToolkit(byte event){
byte[] handler;
envHandler = EnvelopeHandler.getTheHandler();
handler = EnvelopeHandler.getTheHandler();
}

  (9)方法的代码不要太复杂。

    尽量保持方法的代码简单,最大不要超过300个字节。较复杂的方法最好拆分成几个较小的方法。方法的代码少可以提高可读性,并且更容易调试bug。

  (10)确保每个类方法的数量不要超过256个。

    每个类的方法数量限制在256个之内,更多的方法意味着更大的常量池。


首页
产品
新闻
联系