diff --git a/build.xml b/build.xml index 0ac8d10..5a32da1 100644 --- a/build.xml +++ b/build.xml @@ -41,7 +41,7 @@ - + diff --git a/src/openpgpcard/OpenPGPApplet.java b/src/openpgpcard/OpenPGPApplet.java index 8ad8b46..0368fd0 100644 --- a/src/openpgpcard/OpenPGPApplet.java +++ b/src/openpgpcard/OpenPGPApplet.java @@ -47,9 +47,10 @@ public class OpenPGPApplet extends Applet implements ISO7816 { 0x00 }; private static final byte[] EXTENDED_CAP = { - (byte) 0xF0, // Support for GET CHALLENGE + (byte) 0xF2, // Support for GET CHALLENGE // Support for Key Import // PW1 Status byte changeable + // PSO:DEC/ENC with AES 0x00, // Secure messaging using 3DES 0x00, (byte) 0xFF, // Maximum length of challenges 0x00, (byte) 0xFF, // Maximum length Cardholder Certificate @@ -129,6 +130,13 @@ public class OpenPGPApplet extends Applet implements ISO7816 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // Pointer to current AES key in use + private AESKey aesKey; + + private AESKey aes128Key; + private AESKey aes256Key; + private Cipher aesCipher; + private Cipher cipher; private RandomData random; @@ -177,7 +185,12 @@ public class OpenPGPApplet extends Applet implements ISO7816 { sig_key = new PGPKey(); dec_key = new PGPKey(); auth_key = new PGPKey(); - + + aes128Key = (AESKey)KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_128, false); + aes256Key = (AESKey)KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_256, false); + aesCipher = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false); + aesKey = aes128Key; + // cipher = Cipher.getInstance(Cipher.ALG_RSA_PKCS1, false); random = RandomData.getInstance(RandomData.ALG_SECURE_RANDOM); @@ -258,14 +271,14 @@ public class OpenPGPApplet extends Applet implements ISO7816 { // COMPUTE DIGITAL SIGNATURE if (p1p2 == (short) 0x9E9A) { le = computeDigitalSignature(apdu); - } // DECIPHER - else if (p1p2 == (short) 0x8086) { + } else if (p1p2 == (short) 0x8086) { le = decipher(apdu); + } else if (p1p2 == (short) 0x8680) { + le = encipher(apdu); } else { ISOException.throwIt(SW_WRONG_P1P2); } - // TODO Add support for encipher command break; @@ -612,19 +625,79 @@ public class OpenPGPApplet extends Applet implements ISO7816 { * @return Length of data written in buffer */ private short decipher(APDU apdu) { - // DECIPHER if (!(pw1.isValidated() && pw1_modes[PW1_MODE_NO82])) ISOException.throwIt(SW_SECURITY_STATUS_NOT_SATISFIED); - if (!dec_key.getPrivate().isInitialized()) + + short len = 0; + + // Check padding indicator + if (buffer[0] == 0x00) { + // RSA + if (!dec_key.getPrivate().isInitialized()) + ISOException.throwIt(SW_CONDITIONS_NOT_SATISFIED); + + // Copy data to be decrypted to tmp, omit padding indicator + short length = Util.arrayCopyNonAtomic(buffer, (short) 1, tmp, _0, + (short) (in_received - 1)); + + cipher.init(dec_key.getPrivate(), Cipher.MODE_DECRYPT); + len = cipher.doFinal(tmp, _0, length, buffer, _0); + } else if (buffer[0] == 0x02){ + // AES + if (!aesKey.isInitialized()) + ISOException.throwIt(SW_CONDITIONS_NOT_SATISFIED); + + // Check whether data is multiple of blocksize (16). The last 4 bits of the length should be 0 + if(((in_received - 1) & 0x0F) != 0x00) { + ISOException.throwIt(SW_WRONG_LENGTH); + } + + // Copy data to be decrypted to tmp, omit padding indicator + short length = Util.arrayCopyNonAtomic(buffer, (short) 1, tmp, _0, + (short) (in_received - 1)); + + aesCipher.init(aesKey, Cipher.MODE_DECRYPT); + len = aesCipher.doFinal(tmp, _0, length, buffer, _0); + } else { + ISOException.throwIt(SW_CONDITIONS_NOT_SATISFIED); + } + + return len; + } + + /** + * Provide the PSO: ENCIPHER command (INS 2A, P1P2 8680) + * + * Encrypt the data provided using the AES key stored in DO D5. + * + * Before using this method PW1 has to be verified with mode No. 82. + * + * @param apdu + * @return Length of data written in buffer + */ + private short encipher(APDU apdu) { + if (!(pw1.isValidated() && pw1_modes[PW1_MODE_NO82])) + ISOException.throwIt(SW_SECURITY_STATUS_NOT_SATISFIED); + + if (!aesKey.isInitialized()) ISOException.throwIt(SW_CONDITIONS_NOT_SATISFIED); - // Copy data to be decrypted to tmp, omit padding indicator - short length = Util.arrayCopyNonAtomic(buffer, (short) 1, tmp, _0, - (short) (in_received - 1)); - - cipher.init(dec_key.getPrivate(), Cipher.MODE_DECRYPT); - return cipher.doFinal(tmp, _0, length, buffer, _0); - } + // Check whether data is multiple of blocksize (16). The last 4 bits of the length should be 0 + if((in_received & 0x0F) != 0x00) { + ISOException.throwIt(SW_WRONG_LENGTH); + } + + // Copy data to be encrypted to tmp + Util.arrayCopyNonAtomic(buffer, _0, tmp, _0, in_received); + + short len = 1; + // Set padding indicator in output + buffer[0] = 0x02; + + aesCipher.init(aesKey, Cipher.MODE_ENCRYPT); + len += aesCipher.doFinal(tmp, _0, in_received, buffer, (short)1); + return len; + } /** * Provide the INTERNAL AUTHENTICATE command (INS 88) @@ -1079,6 +1152,24 @@ public class OpenPGPApplet extends Applet implements ISO7816 { } break; + // D5 - AES-Key for PSO:ENC/DEC + case (short) 0x00D5: + // Check the length for the provided data + if (in_received == (KeyBuilder.LENGTH_AES_128 / 8)) { + aes128Key.setKey(buffer, _0); + aesKey = aes128Key; + aes256Key.clearKey(); + } else if (in_received == (KeyBuilder.LENGTH_AES_256 / 8)) { + aes256Key.setKey(buffer, _0); + aesKey = aes256Key; + aes128Key.clearKey(); + } else { + ISOException.throwIt(SW_WRONG_LENGTH); + } + + + break; + // D1 - SM-Key-ENC case (short) 0x00D1: sm.setSessionKeyEncryption(buffer, _0); diff --git a/test/openpgpcard/OpenPGPAppletTest.java b/test/openpgpcard/OpenPGPAppletTest.java index 19e7011..dbb3842 100644 --- a/test/openpgpcard/OpenPGPAppletTest.java +++ b/test/openpgpcard/OpenPGPAppletTest.java @@ -4,6 +4,7 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import java.math.BigInteger; +import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; @@ -15,6 +16,11 @@ import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import javax.smartcardio.CommandAPDU; +import javax.smartcardio.ResponseAPDU; import org.junit.Before; import org.junit.BeforeClass; @@ -22,8 +28,6 @@ import org.junit.Test; import com.licel.jcardsim.smartcardio.CardSimulator; -import javax.smartcardio.*; - import javacard.framework.AID; public class OpenPGPAppletTest { @@ -83,6 +87,9 @@ public class OpenPGPAppletTest { static byte[] ADMIN_PIN_NEW = new byte[] { 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31 }; RSAPublicKey publicKey; + SecretKeySpec aes128KeySpec; + SecretKeySpec aes256KeySpec; + IvParameterSpec ivSpec = new IvParameterSpec(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); private static String CHARS = "0123456789ABCDEF"; @@ -141,9 +148,14 @@ public class OpenPGPAppletTest { simulator.installApplet(aid, OpenPGPApplet.class, bArray, (short) 0, (byte) bArray.length); simulator.selectApplet(aid); + // Construct RSA public key RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(new BigInteger("B0AABBCB33DB653EA3C0B71231305455489E8107B7B0A5400951519DE51C3ACF3C69EE96BC1DFE6A59CAD1F8889433096930E077FC2AEFA0D9104B1230A4AD282BAFA0ED434BAB96D64145B7E8054B88AFF1385CFF7879152DC7AC34DD5F17826C177D9173D6094396237A7E560122DFD46F9FBCBFFD27A3E1191F08174F0980BAFDCF45613A03B198C4E6C880E96226AD9E9D3CD08BF05412E8EDD49B267702C2A4766805B38D137191AF2B52991F9ABC49E7C02FCA8C7F617C39CB968894A5A773D5B000912A683F9F760DA6D7247DC26C152CA5DA6FDDD50AD8B769EFB87ADF09B792EDB8AE8B2B3D7015C9F62D7EE3F44F1C35A89140BB74C913A079C3A7", 16), new BigInteger("010001", 16)); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); publicKey = (RSAPublicKey) keyFactory.generatePublic(publicKeySpec); + + // Construct AES keys + aes128KeySpec = new SecretKeySpec(new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, "AES"); + aes256KeySpec = new SecretKeySpec(new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, "AES"); } @Test @@ -393,6 +405,32 @@ public class OpenPGPAppletTest { test(command, SW_SECURITY_STATUS_NOT_SATISFIED); } + @Test + public void test_signTwicePWStatus1() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { + byte[] testData = new byte[] { (byte)0xAB }; + + test_importSignKey(); + + // Enable multiple signatures per authentication + test_adminPINValid(); + command = new CommandAPDU(CLA_DEFAULT, INS_PUT_DATA_DA, 0x00, 0xC4, new byte[] { 0x01 }); + test(command, SW_NO_ERROR); + + test_userPINValid81(); + + command = new CommandAPDU(CLA_DEFAULT, INS_PERFORM_SECURITY_OPERATION, 0x9E, 0x9A, testData); + test(command, 0x6101, hexToBytes("9E62CCBC302E5FF18C897FC65CA5F5044FDFA2133B53778CA10CF75F929428FADC8135958884DCD7829E32DC3D69D902364DDB37448420DDC9F5F57955CC6CCFD869A32E280482C207877B80CE953352E4B41291E624F7583BA84DC5655D5FEC06FE85304470227337C11F21B3528C0EB626ED01F7AE2DD57BA6F7D2529401EF03047394AFE00B626D65FBB57EE59273D6A37E0CA0BF9958BE75F15989CB77BFC18D445EAD7103B857B6B446B0AA35392B1E902C5B2D31E5B7F1A419016EBAFDE3DF22E42417E870907AF4FF0D376EFF188BD919476CF7F95A013D130ED096F6E5D79F8488B2114AC5D1FA989946411CD571F4DB27247477939457FEA734FF")); + + command = new CommandAPDU(CLA_DEFAULT, INS_GET_RESPONSE, 0x00, 0x00, 0x01); + test(command, SW_NO_ERROR, hexToBytes("DB")); + + command = new CommandAPDU(CLA_DEFAULT, INS_PERFORM_SECURITY_OPERATION, 0x9E, 0x9A, testData); + test(command, 0x6101, hexToBytes("9E62CCBC302E5FF18C897FC65CA5F5044FDFA2133B53778CA10CF75F929428FADC8135958884DCD7829E32DC3D69D902364DDB37448420DDC9F5F57955CC6CCFD869A32E280482C207877B80CE953352E4B41291E624F7583BA84DC5655D5FEC06FE85304470227337C11F21B3528C0EB626ED01F7AE2DD57BA6F7D2529401EF03047394AFE00B626D65FBB57EE59273D6A37E0CA0BF9958BE75F15989CB77BFC18D445EAD7103B857B6B446B0AA35392B1E902C5B2D31E5B7F1A419016EBAFDE3DF22E42417E870907AF4FF0D376EFF188BD919476CF7F95A013D130ED096F6E5D79F8488B2114AC5D1FA989946411CD571F4DB27247477939457FEA734FF")); + + command = new CommandAPDU(CLA_DEFAULT, INS_GET_RESPONSE, 0x00, 0x00, 0x01); + test(command, SW_NO_ERROR, hexToBytes("DB")); + } + @Test public void test_decrypt() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { byte[] testData = new byte[] { (byte)0xAB }; @@ -418,7 +456,7 @@ public class OpenPGPAppletTest { } @Test - public void test_decryptWrongPINMode() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { + public void test_decryptWrongPINMode() { byte[] testData = new byte[] { (byte)0xAB }; test_importDecryptKey(); @@ -426,5 +464,117 @@ public class OpenPGPAppletTest { command = new CommandAPDU(CLA_DEFAULT, INS_PERFORM_SECURITY_OPERATION, 0x80, 0x86, testData); test(command, SW_SECURITY_STATUS_NOT_SATISFIED); - } + } + + @Test + public void test_encryptAES128() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException { + byte[] testData = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }; + + Cipher aesCipher = Cipher.getInstance("AES/CBC/NOPADDING"); + aesCipher.init(Cipher.ENCRYPT_MODE, aes128KeySpec, ivSpec); + byte[] encryptedData = aesCipher.doFinal(testData); + + test_adminPINValid(); + // Import AES key + command = new CommandAPDU(CLA_DEFAULT, INS_PUT_DATA_DA, 0x00, 0xD5, new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }); + test(command, SW_NO_ERROR); + + test_userPINValid82(); + + command = new CommandAPDU(CLA_DEFAULT, INS_PERFORM_SECURITY_OPERATION, 0x86, 0x80, testData); + test(command, SW_NO_ERROR, hexToBytes("02" + bytesToHex(encryptedData))); + } + + @Test + public void test_decryptAES128() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException { + byte[] testData = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }; + + Cipher aesCipher = Cipher.getInstance("AES/CBC/NOPADDING"); + aesCipher.init(Cipher.ENCRYPT_MODE, aes128KeySpec, ivSpec); + byte[] encryptedData = aesCipher.doFinal(testData); + + test_adminPINValid(); + // Import AES key + command = new CommandAPDU(CLA_DEFAULT, INS_PUT_DATA_DA, 0x00, 0xD5, new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }); + test(command, SW_NO_ERROR); + + test_userPINValid82(); + + command = new CommandAPDU(CLA_DEFAULT, INS_PERFORM_SECURITY_OPERATION, 0x80, 0x86, hexToBytes("02" + bytesToHex(encryptedData))); + test(command, SW_NO_ERROR, testData); + } + + @Test + public void test_encryptDecryptAES128() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException { + byte[] testData = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }; + + test_adminPINValid(); + // Import AES key + command = new CommandAPDU(CLA_DEFAULT, INS_PUT_DATA_DA, 0x00, 0xD5, new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }); + test(command, SW_NO_ERROR); + + test_userPINValid82(); + + command = new CommandAPDU(CLA_DEFAULT, INS_PERFORM_SECURITY_OPERATION, 0x86, 0x80, testData); + ResponseAPDU response = test(command, SW_NO_ERROR, null); + + command = new CommandAPDU(CLA_DEFAULT, INS_PERFORM_SECURITY_OPERATION, 0x80, 0x86, response.getData()); + test(command, SW_NO_ERROR, testData); + } + + @Test + public void test_encryptAES256() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException { + byte[] testData = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }; + + Cipher aesCipher = Cipher.getInstance("AES/CBC/NOPADDING"); + aesCipher.init(Cipher.ENCRYPT_MODE, aes256KeySpec, ivSpec); + byte[] encryptedData = aesCipher.doFinal(testData); + + test_adminPINValid(); + // Import AES key + command = new CommandAPDU(CLA_DEFAULT, INS_PUT_DATA_DA, 0x00, 0xD5, new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }); + test(command, SW_NO_ERROR); + + test_userPINValid82(); + + command = new CommandAPDU(CLA_DEFAULT, INS_PERFORM_SECURITY_OPERATION, 0x86, 0x80, testData); + test(command, SW_NO_ERROR, hexToBytes("02" + bytesToHex(encryptedData))); + } + + @Test + public void test_decryptAES256() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException { + byte[] testData = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }; + + Cipher aesCipher = Cipher.getInstance("AES/CBC/NOPADDING"); + aesCipher.init(Cipher.ENCRYPT_MODE, aes256KeySpec, ivSpec); + byte[] encryptedData = aesCipher.doFinal(testData); + + test_adminPINValid(); + // Import AES key + command = new CommandAPDU(CLA_DEFAULT, INS_PUT_DATA_DA, 0x00, 0xD5, new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }); + test(command, SW_NO_ERROR); + + test_userPINValid82(); + + command = new CommandAPDU(CLA_DEFAULT, INS_PERFORM_SECURITY_OPERATION, 0x80, 0x86, hexToBytes("02" + bytesToHex(encryptedData))); + test(command, SW_NO_ERROR, testData); + } + + @Test + public void test_encryptDecryptAES256() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException { + byte[] testData = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }; + + test_adminPINValid(); + // Import AES key + command = new CommandAPDU(CLA_DEFAULT, INS_PUT_DATA_DA, 0x00, 0xD5, new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }); + test(command, SW_NO_ERROR); + + test_userPINValid82(); + + command = new CommandAPDU(CLA_DEFAULT, INS_PERFORM_SECURITY_OPERATION, 0x86, 0x80, testData); + ResponseAPDU response = test(command, SW_NO_ERROR, null); + + command = new CommandAPDU(CLA_DEFAULT, INS_PERFORM_SECURITY_OPERATION, 0x80, 0x86, response.getData()); + test(command, SW_NO_ERROR, testData); + } }