学习目标:
简单掌握applet加密解密
学习内容:
首先我们定义两个全局变量,方便让我们指定的apdu命令进行匹配并进行加密解密
// Instruction bytes
private static final byte INS_ENCRYPT = (byte) 0x10;
private static final byte INS_DECRYPT = (byte) 0x20;
然后我们在switch循环中当INS值是INS_ENCRYPT就进行加密,是INS_DECRYPT就进行解密
switch (buffer[ISO7816.OFFSET_INS]) {
case INS_ENCRYPT:
encrypt(apdu);
break;
case INS_DECRYPT:
decrypt(apdu);
break;
default:
// good practice: If you don't know the INStruction, say so:
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
}
当进行加密时,就会进入方法encrypt,进行加密操作,并将加密后的数据进行返回
private void encrypt(APDU apdu) {
byte[] buffer = apdu.getBuffer();
// 检查P1和P2是否正确
if (buffer[ISO7816.OFFSET_P1] != (byte) 0x00 || buffer[ISO7816.OFFSET_P2] != (byte) 0x00) {
ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
}
// 设置加密模式
cipher.init(aesKey, Cipher.MODE_ENCRYPT);
// 加密数据
cipher.doFinal(buffer, ISO7816.OFFSET_CDATA, (short) 16, buffer, ISO7816.OFFSET_CDATA);
// 设置返回值
apdu.setOutgoingAndSend(ISO7816.OFFSET_CDATA, (short) 16);
}
而当我们设置加密模式的时候,需要指定key以及mode,因此我们需要构建密钥,而构建key时需要选择算法以及长度,和是否加密,这里我选择的是TYPE_AES,这里呢也是指定了Cipher为AES ECB模式。考虑到如果我们的apdu命令如果没有带data数据,则会默认使用keyData进行一个加密解密。
private Test3(){
byte[] keyData = new byte[] { (byte) 0xA1, (byte) 0x12, (byte) 0xBC, (byte) 0x8C, (byte) 0xAB, (byte) 0xDC, (byte) 0x4F,
(byte) 0x46, (byte) 0x74, (byte) 0x27, (byte) 0xDA, (byte) 0xE6, (byte) 0x41, (byte) 0xE6, (byte) 0x3D,
(byte) 0xBF};
// 创建密钥,使用128位的AES算法
aesKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_128, false);
// 使用固定的十六字节密钥
aesKey.setKey(keyData, (short) 0);
// 指定算法AES ECB模式(分块解密模式)
cipher = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_ECB_NOPAD, false);
}
而解密呢,则与加密的流程差不多,这里我附上解密方法的代码
private void decrypt(APDU apdu) {
byte[] buffer = apdu.getBuffer();
// 检查P1和P2是否正确
if (buffer[ISO7816.OFFSET_P1] != (byte) 0x00 || buffer[ISO7816.OFFSET_P2] != (byte) 0x00) {
ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
}
// 设置解密模式
cipher.init(aesKey, Cipher.MODE_DECRYPT);
// 解密数据
cipher.doFinal(buffer, ISO7816.OFFSET_CDATA, (short) 16, buffer, ISO7816.OFFSET_CDATA);
// 设置返回值
apdu.setOutgoingAndSend(ISO7816.OFFSET_CDATA, (short) 16);
}
最后然我们一起在JCOP shell测试一下,看程序是否正确
这里看到我们加密解密成功了,状态也是90 00,这次的学习就到这里吧!