====== AES Sample Code ======
[[ https://javacardos.com/javacardforum/download/file.php?id=543| Download Sample Code ]] [[https://javacardos.com/javacardforum/viewtopic.php?f=31&t=735| Discussion]]
/*
* @file AESSample.java
* @version v1.0
* Package AID: 4A617661436172644F53
* Applet AID: 4A617661436172644F5301
* @brief The ALgorithm of AES Sample Code in JavaCard API Specification
* @comment The purpose of this example is only used to show the usage of API functions and there is no practical significance.
* @copyright Copyright(C) 2016 JavaCardOS Technologies Co., Ltd. All rights reserved.
*/
package JavaCardOS.Sample.Algorithm;
import javacard.framework.*;
import javacard.security.KeyBuilder;
import javacard.security.*;
import javacardx.crypto.*;
public class AESSample extends Applet
{
private static final byte INS_SET_AES_KEY = (byte)0x10;
private static final byte INS_SET_AES_ICV = (byte)0x11;
private static final byte INS_DO_AES_CIPHER = (byte)0x12;
private byte aesKeyLen;
private byte[] aesKey;
private byte[] aesICV;
private Cipher aesEcbCipher;
private Cipher aesCbcCipher;
private Key tempAesKey1;
private Key tempAesKey2;
private Key tempAesKey3;
public AESSample()
{
aesKey = new byte[32];
aesICV = new byte[16];
aesKeyLen = 0;
//Create a AES ECB/CBS object instance of the AES algorithm.
aesEcbCipher = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_ECB_NOPAD, false);
aesCbcCipher = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false);
//Create uninitialized cryptographic keys for AES algorithms
tempAesKey1 = KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT, KeyBuilder.LENGTH_AES_128, false);
tempAesKey2 = KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT, KeyBuilder.LENGTH_AES_192, false);
tempAesKey3 = KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT, KeyBuilder.LENGTH_AES_256, false);
JCSystem.requestObjectDeletion();
}
public static void install(byte[] bArray, short bOffset, byte bLength)
{
new AESSample().register(bArray, (short) (bOffset + 1), bArray[bOffset]);
}
public void process(APDU apdu)
{
if (selectingApplet())
{
return;
}
byte[] buf = apdu.getBuffer();
short len = apdu.setIncomingAndReceive();
switch (buf[ISO7816.OFFSET_INS])
{
case INS_SET_AES_KEY:
// SET_AES_KEY
setAesKey(apdu, len);
break;
case INS_SET_AES_ICV:
// SET_AES_ICV
setAesICV(apdu, len);
break;
case INS_DO_AES_CIPHER:
//DO_AES_CIPHER
doAesCipher(apdu, len);
break;
default:
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
}
}
//Set the key of AES Encrypt/Decrypt
private void setAesKey(APDU apdu, short len)
{
byte[] buffer = apdu.getBuffer();
byte keyLen = 0;
switch (buffer[ISO7816.OFFSET_P1])
{
case (byte)0x01:
if (len != 16) // The length of key is 16 bytes
{
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}
keyLen = (byte)16;
break;
case (byte)0x02:
if (len != 24) //The length of key is 24 bytes
{
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}
keyLen = (byte)24;
break;
case (byte)0x03:
if (len != 32) //The length of key is 32 bytes
{
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}
keyLen = (byte)32;
break;
default:
ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
break;
}
JCSystem.beginTransaction();
//Copy the incoming AES Key value to the global variable 'aesKey'
Util.arrayCopy(buffer, ISO7816.OFFSET_CDATA, aesKey, (short)0, len);
aesKeyLen = keyLen;
JCSystem.commitTransaction();
}
//Set AES ICV, ICV is the initial vector
private void setAesICV(APDU apdu, short len)
{
if (len != 16)
{
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}
//Copy the incoming ICV value to the global variable 'aesICV'
Util.arrayCopy(apdu.getBuffer(), ISO7816.OFFSET_CDATA, aesICV, (short)0, (short)16);
}
//Sets the Key data, and return the AESKey object. The plaintext length of input key data is 16/24/32 bytes.
private Key getAesKey()
{
Key tempAesKey = null;
switch (aesKeyLen)
{
case (byte)16:
tempAesKey = tempAesKey1;
break;
case (byte)24:
tempAesKey = tempAesKey2;
break;
case (byte)32:
tempAesKey = tempAesKey3;
break;
default:
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
break;
}
//Set the 'aesKey' key data value into the internal representation
((AESKey)tempAesKey).setKey(aesKey, (short)0);
return tempAesKey;
}
//AES algorithm encrypt and decrypt
private void doAesCipher(APDU apdu, short len)
{
//The byte length to be encrypted/decrypted must be a multiple of 16
if (len <= 0 || len % 16 != 0)
{
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}
byte[] buffer = apdu.getBuffer();
Key key = getAesKey();
byte mode = buffer[ISO7816.OFFSET_P1] == (byte)0x00 ? Cipher.MODE_ENCRYPT : Cipher.MODE_DECRYPT;
Cipher cipher = buffer[ISO7816.OFFSET_P2] == (byte)0x00 ? aesEcbCipher : aesCbcCipher;
//Initializes the 'cipher' object with the appropriate Key and algorithm specific parameters.
//AES algorithms in CBC mode expect a 16-byte parameter value for the initial vector(IV)
if (cipher == aesCbcCipher)
{
cipher.init(key, mode, aesICV, (short)0, (short)16);
}
else
{
cipher.init(key, mode);
}
//This method must be invoked to complete a cipher operation. Generates encrypted/decrypted output from all/last input data.
cipher.doFinal(buffer, ISO7816.OFFSET_CDATA, len, buffer, (short)0);
apdu.setOutgoingAndSend((short)0, len);
}
}
The test script of AES is as follows: [[https://javacardos.com/javacardforum/download/file.php?id=549|Download Test Script]]
//The test script of AES
//Copyright(C) JavaCardOS Technologies Co., Ltd. All rights reserved.
//AES Select Applet
00A404000B4A617661436172644F530100;
//AES-CBC-256Key
//set Key CBC-256 Key Length
80100300209AF0BF0D5D711B9E01C59ED55A015C8AB2D3980010B72CBBBA6E2C91F8ADC604;
//set ICV
80110000101C64F340DD29C891B4826509A1FF64E8;
//CBC encrypt
//expect: E2E6C4AB4D212BB52A292B6368137D3E9000
8012000110C9C9332182CFC8AB48908A972D283582;
//AES-CBC-256Key
//set Key CBC-256 Key Length
8010030020B57260D2B78CF4B37F315000B7720F796A3E379E6934BB21EEB6449C803F3080;
//set ICV
80110000103DCBD02A91EA65D1A2E23A53584AA18A;
//CBC decrypt
//expect:722D19DB28EF9088CB5FE90784C16A3E336156D29CC4421A398B9C22C63E2F074FADA2B9D95AF7BBE2F246000E20AEB03BAFBE61E2768E92FDF537B29ADA75FF93BDBE4DE2A8F053229B6C5062F8F23D71546689B0F48622B59A6BA30EF151D53B3616B9FEF7AE9A95CE56EABB292E9BAF3B380B915BBFD3AB3238AF99F56E4EED4682D146DA18F92902D1A085EE9E609000
80120101902D5D6440C517EBC13EFC8E2471918C3C34620A287D9C5A84CBD77CDCC134E56614A880F0A897F317F6A523BAB1C9FAAEA9A368B3EF0FA7A73AFAC4FA89745B620A07A2D03B47A8A24FABDF1AD39BD90F91CA4FE2B5C667B42ECE36D657E38481D721D0C8C65094CA11B7CB2C1F30AFC7B482C79D16EA21126FFBDD5973A9EB2C42A014C090DA3FF80370EDD9DCB0073E;
//AES-ECB-192Key
//set Key
801002001800CF30D306C95D3851B85D11786917BA3C28F8FB0E349524;
//ECB encrypt
//expect:1108C33BCAB8B43FB229AFDACEBB7859A498371191DEBCD1E40916E2C72835E41B3F536A27D35429FED70B2973862F1C9000
801200003012A4D1CDB906E044B14CC2BC2D6DE6FBAE708568CC248266331195E0ECAEA825DED581F79473A2DE40846DC3003F8CB9;
//AES-ECB-192Key
//set Key
8010020018DCC25F4F162E0F9B5A2617F6341AF37AA41C3EE4C1F27848;
//ECB decrypt
//expect:475161225A00DBBD3CDEB304BB5F8FCCD40B266DB5BC164E23F646EB542D6BA988099087CDC1B98749F61D3EDFFAAAA50564D6BBCF49C9F3267E86877521A18C1897DA808BD356E65261B2F208CE065B9000
801201005006E99C9EBAB3D08F7EE117838078B3C7AF419F797B7672E2DBC2850695695878BAC232736FEE0827F3C4A051DE0BF70EA7ECDFF169A6EC53E78491EACD0D879E397A6E97796DB79B17DFC197125A427B;