问题
I'm new to the whole topic of Java Card and tried to look at a few code examples to get a better understanding. I found a sample for AES usage in the oracle forum but have a few problems with the following part:
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);
}
From my understanding this code takes the first 24 data bytes from the incoming APDU, encrypts them and puts them into the byte array a. Then it takes the next 24 data bytes, decrypts them and puts them into a too.
But the following commands don't use these output data since
apdu.sendBytesLong(b, (short) dataOffset, (short) 72);
uses b for the output data ... this is probably not correct so please help me understand where I went wrong.
Also: what would a simple command APDU for encrypting a small text with this and the corresponding answer look like ?
回答1:
The code from the Oracle forum is not very good, actually. It does not follow basic rules of memory usage and it is not a real-world example at all. Moreover, it would be very slow and it could even damage your smart card if used too often.
I think you should firstly read through the Java Card tutorials and learn what APDU is and something about its structure, see this question:
How to get started with Java Cards?
Then you could proceed to Java Card encryption/decryption. Something like this might help you:
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);
}
}
}
Note: I initialize the key value from an input command in my example. My key is stored in RAM, which means the value disappears after each card reset or another applet selection. This does not have to fit your business case and it may be wiser to generate a secret key on the card just once and store it in the persistent memory. If so, you have to use a different keytype: KeyBuilder.TYPE_AES
instead of KeyBuilder.TYPE_AES_TRANSIENT_DESELECT
.
来源:https://stackoverflow.com/questions/32395400/en-decryption-output-in-java-card-corresponding-apdus