En-/Decryption输出在Java卡+对应的APDU
En-/Decryption output in Java Card + corresponding APDUs
我是 Java Card 整个主题的新手,并尝试查看一些代码示例以更好地理解。
我在 oracle forum 中找到了 AES 使用示例,但以下部分存在一些问题:
private void doAES(APDU apdu)
{
byte b[] = apdu.getBuffer();
short incomingLength = (short) (apdu.setIncomingAndReceive());
if (incomingLength != 24) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
//perform encryption and append results in APDU Buffer a[] automatically
cipherAES.init(aesKey, Cipher.MODE_ENCRYPT);
cipherAES.doFinal(b, (short) dataOffset, incomingLength, a, (short) (dataOffset + 24));
cipherAES.init(aesKey, Cipher.MODE_DECRYPT);
cipherAES.doFinal(b, (short) (dataOffset + 24), incomingLength, a, (short) (dataOffset + 48));
// Send results
apdu.setOutgoing();
apdu.setOutgoingLength((short) 72);
apdu.sendBytesLong(b, (short) dataOffset, (short) 72);
}
根据我的理解,这段代码从传入的 APDU 中获取前 24 个数据字节,对它们进行加密并将它们放入字节数组 a 中。
然后它获取接下来的 24 个数据字节,将它们解密并放入一个太。
但是以下命令不使用这些输出数据,因为
apdu.sendBytesLong(b, (short) dataOffset, (short) 72);
使用 b 作为输出数据...这可能不正确,所以请帮助我了解哪里出错了。
另外:用这个加密小文本的简单命令 APDU 和相应的答案是什么样的?
Oracle 论坛的代码实际上不是很好。它不遵循内存使用的基本规则,根本不是真实世界的例子。而且,它会很慢,如果经常使用它甚至会损坏您的智能卡。
我觉得你应该先通读一下Java卡片教程,了解什么是APDU及其结构,看这个问题:
How to get started with Java Cards?
然后你可以继续Java卡片encryption/decryption。这样的事情可能对你有帮助:
public class MiniApplet extends Applet {
public static void install(byte[] bArray, short bOffset, byte bLength) {
// GP-compliant JavaCard applet registration
new MiniApplet().register(bArray, (short) (bOffset + 1),
bArray[bOffset]);
}
private final AESKey aesKey = (AESKey)KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT, KeyBuilder.LENGTH_AES_128, false);
private final Cipher aes = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false);
public void process(APDU apdu) {
// Good practice: Return 9000 on SELECT
if (selectingApplet()) {
return;
}
final byte[] buf = apdu.getBuffer();
final short dataLen = apdu.setIncomingAndReceive();
final byte ins = buf[ISO7816.OFFSET_INS];
switch (ins) {
case (byte) 0x00: //KEY VALUE INIT FROM APDU
if (dataLen != 16) //checking key value length
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH)
aesKey.setKey(buf, ISO7816.OFFSET_CDATA);
break;
case (byte) 0x01: //DECRYPTION
case (byte) 0x02: //ENCRYPTION
if ((dataLen & 0x000F) != 0) //checking if input data is block-aligned
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH)
if (!aesKey.isInitialized())
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
aes.init(aesKey, (ins == 0x02) ? Cipher.MODE_ENCRYPT : Cipher.MODE_DECRYPT);
aes.doFinal(buf, ISO7816.OFFSET_CDATA, dataLen, buf, ISO7816.OFFSET_CDATA);
apdu.setOutgoingAndSend(ISO7816.OFFSET_CDATA, dataLen);
break;
default:
// good practice: If you don't know the INStruction, say so:
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
}
}
}
注意: 在我的示例中,我从输入命令初始化键值。我的密钥存储在 RAM 中,这意味着每次重置卡或选择另一个小程序后,该值都会消失。这不一定适合您的业务案例,更明智的做法是只在卡上生成一次密钥并将其存储在持久性内存中。如果是这样,您必须使用不同的键类型:KeyBuilder.TYPE_AES
而不是 KeyBuilder.TYPE_AES_TRANSIENT_DESELECT
。
我是 Java Card 整个主题的新手,并尝试查看一些代码示例以更好地理解。 我在 oracle forum 中找到了 AES 使用示例,但以下部分存在一些问题:
private void doAES(APDU apdu)
{
byte b[] = apdu.getBuffer();
short incomingLength = (short) (apdu.setIncomingAndReceive());
if (incomingLength != 24) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
//perform encryption and append results in APDU Buffer a[] automatically
cipherAES.init(aesKey, Cipher.MODE_ENCRYPT);
cipherAES.doFinal(b, (short) dataOffset, incomingLength, a, (short) (dataOffset + 24));
cipherAES.init(aesKey, Cipher.MODE_DECRYPT);
cipherAES.doFinal(b, (short) (dataOffset + 24), incomingLength, a, (short) (dataOffset + 48));
// Send results
apdu.setOutgoing();
apdu.setOutgoingLength((short) 72);
apdu.sendBytesLong(b, (short) dataOffset, (short) 72);
}
根据我的理解,这段代码从传入的 APDU 中获取前 24 个数据字节,对它们进行加密并将它们放入字节数组 a 中。 然后它获取接下来的 24 个数据字节,将它们解密并放入一个太。
但是以下命令不使用这些输出数据,因为
apdu.sendBytesLong(b, (short) dataOffset, (short) 72);
使用 b 作为输出数据...这可能不正确,所以请帮助我了解哪里出错了。
另外:用这个加密小文本的简单命令 APDU 和相应的答案是什么样的?
Oracle 论坛的代码实际上不是很好。它不遵循内存使用的基本规则,根本不是真实世界的例子。而且,它会很慢,如果经常使用它甚至会损坏您的智能卡。
我觉得你应该先通读一下Java卡片教程,了解什么是APDU及其结构,看这个问题:
How to get started with Java Cards?
然后你可以继续Java卡片encryption/decryption。这样的事情可能对你有帮助:
public class MiniApplet extends Applet {
public static void install(byte[] bArray, short bOffset, byte bLength) {
// GP-compliant JavaCard applet registration
new MiniApplet().register(bArray, (short) (bOffset + 1),
bArray[bOffset]);
}
private final AESKey aesKey = (AESKey)KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT, KeyBuilder.LENGTH_AES_128, false);
private final Cipher aes = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false);
public void process(APDU apdu) {
// Good practice: Return 9000 on SELECT
if (selectingApplet()) {
return;
}
final byte[] buf = apdu.getBuffer();
final short dataLen = apdu.setIncomingAndReceive();
final byte ins = buf[ISO7816.OFFSET_INS];
switch (ins) {
case (byte) 0x00: //KEY VALUE INIT FROM APDU
if (dataLen != 16) //checking key value length
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH)
aesKey.setKey(buf, ISO7816.OFFSET_CDATA);
break;
case (byte) 0x01: //DECRYPTION
case (byte) 0x02: //ENCRYPTION
if ((dataLen & 0x000F) != 0) //checking if input data is block-aligned
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH)
if (!aesKey.isInitialized())
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
aes.init(aesKey, (ins == 0x02) ? Cipher.MODE_ENCRYPT : Cipher.MODE_DECRYPT);
aes.doFinal(buf, ISO7816.OFFSET_CDATA, dataLen, buf, ISO7816.OFFSET_CDATA);
apdu.setOutgoingAndSend(ISO7816.OFFSET_CDATA, dataLen);
break;
default:
// good practice: If you don't know the INStruction, say so:
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
}
}
}
注意: 在我的示例中,我从输入命令初始化键值。我的密钥存储在 RAM 中,这意味着每次重置卡或选择另一个小程序后,该值都会消失。这不一定适合您的业务案例,更明智的做法是只在卡上生成一次密钥并将其存储在持久性内存中。如果是这样,您必须使用不同的键类型:KeyBuilder.TYPE_AES
而不是 KeyBuilder.TYPE_AES_TRANSIENT_DESELECT
。