Scripting Server

IsoSecureChannel - Reference Documentation

Class to support a secure communication channel via secure messaging according to ISO 7816-4 and CWA 14890 (eSign-K).

This implementation supports 3-TDES and AES keys for MAC and encryption.

For 3-TDES keys the MAC algorithm is ISO 9797 Algorithm 3 (Retail-MAC or EMV-MAC), the encryption algorithm is DES-CBC.

For AES keys the MAC algorithm is AES-CMAC and the encryption algorithm is AES-CBC.

Three policies for handling send sequence counters are available:

SSC_DEFAULT_POLICY

If a send sequence counter for MAC is defined, then it is incremented for each new MAC and prepended to the protected message.

If a send sequence counter for encryption is defined, then it is incremented for each new cryptogram and used as initialisation vector.

SSC_SYNC_POLICY

If a send sequence counter for MAC is defined, then it is incremented for each new MAC and prepended to the protected message.

The same send sequence counter is used as initialisation vector for encrypted data (EAC 2.0 with 3-TDES).

SSC_SYNC_ENC_POLICY

If a send sequence counter for MAC is defined, then it is incremented for each new MAC and prepended to the protected message.

The same send sequence counter is encrypted and the result is used as initialisation vector for encrypted data.┬┤This has the same effect as prepending the message to be encrypted with the SSC (EAC 2.0 with AES).

Index of Methods

Constants

Type Name Description
Number SSC_DEFAULT_POLICY Default SSC policy
Number SSC_SYNC_POLICY Same send sequence counter for MAC and encryption
Number SSC_SYNC_ENC_POLICY Same send sequence counter for MAC and encrypted SSC for encryption

Properties

Type Name Description
ByteString encryptionSendSequenceCounter Current value of send sequence counter for encryption
ByteString MACSendSequenceCounter Current value of send sequence counter for MAC calculation

Constructor

Prototype

IsoSecureChannel(Crypto crypto)

IsoSecureChannel(Crypto crypto, Number policy)

Description

Instantiate an IsoSecureChannel object that allows to wrap command-APDUs and unwrap response-APDUs using secure messaging as defined in ISO 7816-4 and CWA 14890 (eSign-K).

The object instantiated with this constructor must be further initialized using the setEncKey(), setMacKey() and setMACSendSequenceCounter() methods.

The class only supports 3DES/CBC and RetailMAC as cryptographic algorithms using a double or triple length DES key.

Objects of this class can be used in Card.setCredential() and CardFile.setCredential() as credential object.

Arguments

Type Name Description
Crypto crypto Crypto object to use for cryptographic operations
Number policy One of SSC_DEFAULT_POLICY, SSC_SYNC_POLICY or SSC_SYNC_ENC_POLICY

Exceptions

Name Value Description
GPError GPError.INVALID_ARGUMENTS Too many arguments in call

Example


var crypto = new Crypto();
var isc = new IsoSecureChannel(crypto);

setEncKey()

Prototype

void setEncKey(Key kenc)

Description

Set the key to be used for encryption of command-APDUs and decryption of response-APDUs.

Arguments

Type Name Description
Key kenc The encryption key

Return

void The method does not return a value

Exceptions

Name Value Description
GPError GPError.ARGUMENTS_MISSING Too few arguments in call
GPError GPError.INVALID_ARGUMENTS Too many arguments in call
GPError GPError.INVALID_TYPE Argument must be of type Key

Example


var kencval = new ByteString("7CA110454A1A6E570131D9619DC1376E4A1A6E570131D961", HEX);
var kenc = new Key();
kenc.setComponent(Key.DES, kencval);

isc.setEncKey(kenc);

setMacKey()

Prototype

void setMacKey(Key kmac)

Description

Set the key to be used for calculating and verifying the message authentication code (MAC).

Arguments

Type Name Description
Key kmac The message authentication key

Return

void The method does not return a value

Exceptions

Name Value Description
GPError GPError.ARGUMENTS_MISSING Too few arguments in call
GPError GPError.INVALID_ARGUMENTS Too many arguments in call
GPError GPError.INVALID_TYPE Argument must be of type Key

Example


var kmacval = new ByteString("0131D9619DC1376E7CA110454A1A6E579DC1376E7CA11045", HEX);
var kmac = new Key();
kmac.setComponent(Key.DES, kmacval);

isc.setMacKey(kmac);

setMACSendSequenceCounter()

Prototype

void setMACSendSequencCounter(ByteString ssc)

Description

Set the initial value for the send sequence counter using for message authentication codes.

If a send sequence counter is defined, then this counter will be incremented for each command or response APDU that contains a MAC.

The deprecated setSendSequenceCounter() maps to this method.

Arguments

Type Name Description
ByteString ssc The initial value for the send sequence counter or null

Return

void The method does not return a value

Exceptions

Name Value Description
GPError GPError.ARGUMENTS_MISSING Too few arguments in call
GPError GPError.INVALID_ARGUMENTS Too many arguments in call
GPError GPError.INVALID_TYPE The argument must be of type ByteString

Example


var ssc = new ByteString("FFFFFFFFFFFFFFF6", HEX);
isc.setMACSendSequenceCounter(ssc);

setEncryptionSendSequenceCounter()

Prototype

void setEncryptionSendSequencCounter(ByteString ssc)

Description

Set the initial value for the send sequence counter used for encryption.

If a send sequence counter is defined, then this counter will be incremented for each command or response APDU that contains encrypted contents.

Arguments

Type Name Description
ByteString ssc The initial value for the send sequence counter or null

Return

void The method does not return a value

Exceptions

Name Value Description
GPError GPError.ARGUMENTS_MISSING Too few arguments in call
GPError GPError.INVALID_ARGUMENTS Too many arguments in call
GPError GPError.INVALID_TYPE The argument must be of type ByteString

Example


// see setMACSendSequenceCounter() for an example.

setIV()

Prototype

void setIV(ByteString iv)

Description

Set the initial vector for DES/CBC encryption and decryption.

The default value used without using this method is '0000000000000000'.

Arguments

Type Name Description
ByteString iv The initial vector or null

Return

void The method does not return a value

Exceptions

Name Value Description
GPError GPError.ARGUMENTS_MISSING Too few arguments in call
GPError GPError.INVALID_ARGUMENTS Too many arguments in call
GPError GPError.INVALID_TYPE The argument must be of type ByteString

Example


var iv = new ByteString("1111111111111111", HEX);
isc.setIV(iv);

setMacLength()

Prototype

void setMacLength(Number maclen)

Description

Set the length of the message authentication code as number of most significant bytes from the last cryptographic operation.

The default value is 8 byte.

Arguments

Type Name Description
Number maclen The number of leftmost / most significant bytes to be used as MAC

Return

void The method does not return a value

Exceptions

Name Value Description
GPError GPError.ARGUMENTS_MISSING Too few arguments in call
GPError GPError.INVALID_ARGUMENTS Too many arguments in call
GPError GPError.INVALID_TYPE The argument must be of type ByteString

Example


isc.setMacLength(8);

wrap()

Prototype

ByteString wrap(ByteString apduToWrap, Number usageQualifier)

Description

Wrap a command-APDU with a secure messaging block.

Depending on the usageQualifier, no transformation (0), an encryption (Card.CENC), a MAC calculation (Card.CPRO) or both (Card.CENC|Card.CPRO) is performed.

The APDU is transformed as defined in ISO 7816-4 and CWA 14890 (eSignK).

Arguments

Type Name Description
ByteString apduToWrap The command APDU to wrap
Number usageQualifier A bitwise combination of Card.CPRO and Card.CENC.

Return

ByteString Wrapped command APDU

Exceptions

Name Value Description
GPError GPError.ARGUMENTS_MISSING Too few arguments in call
GPError GPError.INVALID_ARGUMENTS Too many arguments in call
GPError GPError.INVALID_TYPE The type of the argument passed to the method is invalid
GPError GPError.INVALID_MECH The cryptographic operating is not supported by the selected crypto service

Example


// #### Using 3-TDES with short APDUs ####

var ssc = new ByteString("FFFFFFFFFFFFFFF6", HEX);
isc.setMACSendSequenceCounter(ssc);

// Case 1 Command APDU CLA=00 INS=10 P1=20 P2=30
var apdu = new ByteString("00102030", HEX);

// Case 1 Plain 	-> CLA'|INS|P1|P2
var r = isc.wrap(apdu, 0);

// Test result
assert(r.toString(16) == "08102030");
assert(isc.sendSequenceCounter.toString(16) == "FFFFFFFFFFFFFFF6");



// Case 1 CENC  	-> CLA'|INS|P1|P2
var r = isc.wrap(apdu, Card.CENC);

// Test result
assert(r.toString(16) == "08102030");
assert(isc.sendSequenceCounter.toString(16) == "FFFFFFFFFFFFFFF6");



// Case 1 CPRO		-> CLA'|INS|P1|P2|Lc'|TLmac
var r = isc.wrap(apdu, Card.CPRO);

// Test result
var exp = new ByteString("0C1020300A8E08", HEX);
var mac = crypto.sign(kmac, Crypto.DES_MAC_EMV, new ByteString(
            "FFFFFFFFFFFFFFF70C10203080000000", HEX));
exp = exp.concat(mac);
assert(r.equals(exp));



// Case 1 CENC|CPRO	-> CLA'|INS|P1|P2|Lc'|TLmac
var r = isc.wrap(apdu, Card.CENC|Card.CPRO);

// Test result
var exp = new ByteString("0C1020300A8E08", HEX);
var mac = crypto.sign(kmac, Crypto.DES_MAC_EMV, new ByteString(
            "FFFFFFFFFFFFFFF80C10203080000000", HEX));
exp = exp.concat(mac);
assert(r.equals(exp));



// Case 2s Command APDU CLA=00 INS=10 P1=20 P2=30 Le=80
var apdu = new ByteString("0010203080", HEX);

// Case 2s Plain		-> CLA'|INS|P1|P2|Lc'|TLle|00
var r = isc.wrap(apdu, 0);

// Test result
assert(r.toString(16) == "081020300396018000");
assert(isc.sendSequenceCounter.toString(16) == "FFFFFFFFFFFFFFF8");



// Case 2s CENC		-> CLA'|INS|P1|P2|Lc'|TLle|00
var r = isc.wrap(apdu, Card.CENC);

// Test result
assert(r.toString(16) == "081020300396018000");
assert(isc.sendSequenceCounter.toString(16) == "FFFFFFFFFFFFFFF8");



// Case 2s CPRO		-> CLA'|INS|P1|P2|Lc'|TLle|TLmac|00
var r = isc.wrap(apdu, Card.CPRO);

// Test result
var exp = new ByteString("0C1020300D9701808E08", HEX);
var mac = crypto.sign(kmac, Crypto.DES_MAC_EMV, new ByteString(
            "FFFFFFFFFFFFFFF90C102030800000009701808000000000", HEX));
exp = exp.concat(mac).concat(new ByteString("00", HEX));
assert(r.equals(exp));



// Case 2s CENC|CPRO	-> CLA'|INS|P1|P2|Lc'|TLle|TLmac|00
var r = isc.wrap(apdu, Card.CPRO|Card.CENC);

// Test result
var exp = new ByteString("0C1020300D9701808E08", HEX);
var mac = crypto.sign(kmac, Crypto.DES_MAC_EMV, new ByteString(
            "FFFFFFFFFFFFFFFA0C102030800000009701808000000000", HEX));
exp = exp.concat(mac).concat(new ByteString("00", HEX));
assert(r.equals(exp));



// Case 3s Command APDU CLA=00 INS=10 P1=20 P2=30 Lc=04 Data=41424344
var apdu = new ByteString("001020300441424344", HEX);

// Case 3s Plain		-> CLA'|INS|P1|P2|Lc'|TLplain
var r = isc.wrap(apdu, 0);

// Test result
assert(r.toString(16) == "0810203006800441424344");
assert(isc.sendSequenceCounter.toString(16) == "FFFFFFFFFFFFFFFA");



// Case 3s CENC		-> CLA'|INS|P1|P2|Lc'|TLenc
var r = isc.wrap(apdu, Card.CENC);

// Test result
var exp = new ByteString("081020300B860901", HEX);
var enc = crypto.encrypt(kenc, Crypto.DES_CBC, 
            new ByteString("4142434480000000", HEX), iv);
exp = exp.concat(enc);
assert(r.equals(exp));
assert(isc.sendSequenceCounter.toString(16) == "FFFFFFFFFFFFFFFB");



// Case 3s CPRO		-> CLA'|INS|P1|P2|Lc'|TLplain|TLmac
var r = isc.wrap(apdu, Card.CPRO);

// Test result
var exp = new ByteString("0C102030108104414243448E08", HEX);
var mac = crypto.sign(kmac, Crypto.DES_MAC_EMV, new ByteString(
            "FFFFFFFFFFFFFFFC0C102030800000008104414243448000", HEX));
exp = exp.concat(mac);
assert(r.equals(exp));


// Case 3s CENC|CPRO	-> CLA'|INS|P1|P2|Lc'|TLenc|TLmac
var r = isc.wrap(apdu, Card.CENC|Card.CPRO);

// Test result
var exp = new ByteString("0C10203015870901", HEX);
var enc = crypto.encrypt(kenc, Crypto.DES_CBC, 
            new ByteString("4142434480000000", HEX), iv);
exp = exp.concat(enc);
exp = exp.concat(new ByteString("8E08", HEX));
var macinp = new ByteString("FFFFFFFFFFFFFFFD0C10203080000000870901", HEX);
macinp = macinp.concat(enc);
macinp = macinp.concat(new ByteString("8000000000", HEX));
var mac = crypto.sign(kmac, Crypto.DES_MAC_EMV, macinp);
exp = exp.concat(mac);
assert(r.equals(exp));



// Case 4s Command APDU CLA=00 INS=10 P1=20 P2=30 Lc=04 Data=41424344 Le=80
var apdu = new ByteString("00102030044142434480", HEX);

// Case 4s Plain		-> CLA'|INS|P1|P2|Lc'|TLplain|TLle|00
var r = isc.wrap(apdu, 0);

// Test result
assert(r.toString(16) == "081020300980044142434496018000");
assert(isc.sendSequenceCounter.toString(16) == "FFFFFFFFFFFFFFFD");



// Case 4s CENC		-> CLA'|INS|P1|P2|Lc'|TLenc|TLle|00
var r = isc.wrap(apdu, Card.CENC);

// Test result
var exp = new ByteString("081020300E860901", HEX);
var enc = crypto.encrypt(kenc, Crypto.DES_CBC, 
            new ByteString("4142434480000000", HEX), iv);
exp = exp.concat(enc);
exp = exp.concat(new ByteString("96018000", HEX));
assert(r.equals(exp));
assert(isc.sendSequenceCounter.toString(16) == "FFFFFFFFFFFFFFFE");



// Case 4s CPRO		-> CLA'|INS|P1|P2|Lc'|TLplain|TLle|TLmac|00
var r = isc.wrap(apdu, Card.CPRO);

// Test result
var exp = new ByteString("0C102030138104414243449701808E08", HEX);
var mac = crypto.sign(kmac, Crypto.DES_MAC_EMV, new ByteString(
            "FFFFFFFFFFFFFFFF0C1020308000000081044142434497018080000000000000", HEX));
exp = exp.concat(mac).concat(new ByteString("00", HEX));
assert(r.equals(exp));



// Case 4s CENC|CPRO	-> CLA'|INS|P1|P2|Lc'|TLenc|TLle|TLmac|00
var r = isc.wrap(apdu, Card.CENC|Card.CPRO);

// Test result
var exp = new ByteString("0C10203018870901", HEX);
var enc = crypto.encrypt(kenc, Crypto.DES_CBC, 
            new ByteString("4142434480000000", HEX), iv);
exp = exp.concat(enc);
exp = exp.concat(new ByteString("9701808E08", HEX));
var macinp = new ByteString("00000000000000000C10203080000000870901", HEX);
macinp = macinp.concat(enc);
macinp = macinp.concat(new ByteString("970180", HEX));
macinp = macinp.concat(new ByteString("8000", HEX));
var mac = crypto.sign(kmac, Crypto.DES_MAC_EMV, macinp);
exp = exp.concat(mac).concat(new ByteString("00", HEX));
assert(r.equals(exp));


//#### Using 3-TDES with extended APDUs ####

var ssc = new ByteString("FFFFFFFFFFFFFFF8", HEX);
isc.setMACSendSequenceCounter(ssc);

//Case 2e Command APDU CLA=00 INS=10 P1=20 P2=30 Le=000180
var apdu = new ByteString("00102030000180", HEX);

// Case 2e Plain		-> CLA'|INS|P1|P2|Lc'|TLle|00
var r = isc.wrap(apdu, 0);

// Test result
assert(r.toString(16) == "08102030000004960201800000");
assert(isc.sendSequenceCounter.toString(16) == "FFFFFFFFFFFFFFF8");



// Case 2e CENC		-> CLA'|INS|P1|P2|Lc'|TLle|00
var r = isc.wrap(apdu, Card.CENC);

// Test result
assert(r.toString(16) == "08102030000004960201800000");
assert(isc.sendSequenceCounter.toString(16) == "FFFFFFFFFFFFFFF8");



// Case 2e CPRO		-> CLA'|INS|P1|P2|Lc'|TLle|TLmac|00
var r = isc.wrap(apdu, Card.CPRO);

// Test result
var exp = new ByteString("0C10203000000E970201808E08", HEX);
var mac = crypto.sign(kmac, Crypto.DES_MAC_EMV, new ByteString(
            "FFFFFFFFFFFFFFF90C102030800000009702018080000000", HEX));
exp = exp.concat(mac).concat(new ByteString("0000", HEX));
// print("Expected " + exp);
// print("Received " + r);
assert(r.equals(exp));



// Case 2e CENC|CPRO	-> CLA'|INS|P1|P2|Lc'|TLle|TLmac|00
var r = isc.wrap(apdu, Card.CPRO|Card.CENC);

// Test result
var exp = new ByteString("0C10203000000E970201808E08", HEX);
var mac = crypto.sign(kmac, Crypto.DES_MAC_EMV, new ByteString(
            "FFFFFFFFFFFFFFFA0C102030800000009702018080000000", HEX));
exp = exp.concat(mac).concat(new ByteString("0000", HEX));
assert(r.equals(exp));



//Case 3e Command APDU CLA=00 INS=10 P1=20 P2=30 Lc=04 Data=41424344
var apdu = new ByteString("0010203000000441424344", HEX);

// Case 3e Plain		-> CLA'|INS|P1|P2|Lc'|TLplain
var r = isc.wrap(apdu, 0);

// Test result
assert(r.toString(16) == "08102030000006800441424344");
assert(isc.sendSequenceCounter.toString(16) == "FFFFFFFFFFFFFFFA");



// Case 3e CENC		-> CLA'|INS|P1|P2|Lc'|TLenc
var r = isc.wrap(apdu, Card.CENC);

// Test result
var exp = new ByteString("0810203000000B860901", HEX);
var enc = crypto.encrypt(kenc, Crypto.DES_CBC, 
            new ByteString("4142434480000000", HEX), iv);
exp = exp.concat(enc);
assert(r.equals(exp));
assert(isc.sendSequenceCounter.toString(16) == "FFFFFFFFFFFFFFFB");



// Case 3e CPRO		-> CLA'|INS|P1|P2|Lc'|TLplain|TLmac
var r = isc.wrap(apdu, Card.CPRO);

// Test result
var exp = new ByteString("0C1020300000108104414243448E08", HEX);
var mac = crypto.sign(kmac, Crypto.DES_MAC_EMV, new ByteString(
            "FFFFFFFFFFFFFFFC0C102030800000008104414243448000", HEX));
exp = exp.concat(mac);
assert(r.equals(exp));


// Case 3e CENC|CPRO	-> CLA'|INS|P1|P2|Lc'|TLenc|TLmac
var r = isc.wrap(apdu, Card.CENC|Card.CPRO);

// Test result
var exp = new ByteString("0C102030000015870901", HEX);
var enc = crypto.encrypt(kenc, Crypto.DES_CBC, 
            new ByteString("4142434480000000", HEX), iv);
exp = exp.concat(enc);
exp = exp.concat(new ByteString("8E08", HEX));
var macinp = new ByteString("FFFFFFFFFFFFFFFD0C10203080000000870901", HEX);
macinp = macinp.concat(enc);
macinp = macinp.concat(new ByteString("8000000000", HEX));
var mac = crypto.sign(kmac, Crypto.DES_MAC_EMV, macinp);
exp = exp.concat(mac);
assert(r.equals(exp));



//Case 4e Command APDU CLA=00 INS=10 P1=20 P2=30 Lc=000004 Data=41424344 Le=000180
var apdu = new ByteString("00102030000004414243440180", HEX);

// Case 4e Plain		-> CLA'|INS|P1|P2|Lc'|TLplain|TLle|00
var r = isc.wrap(apdu, 0);

// Test result
assert(r.toString(16) == "0810203000000A800441424344960201800000");
assert(isc.sendSequenceCounter.toString(16) == "FFFFFFFFFFFFFFFD");



// Case 4e CENC		-> CLA'|INS|P1|P2|Lc'|TLenc|TLle|00
var r = isc.wrap(apdu, Card.CENC);

// Test result
var exp = new ByteString("0810203000000F860901", HEX);
var enc = crypto.encrypt(kenc, Crypto.DES_CBC, 
            new ByteString("4142434480000000", HEX), iv);
exp = exp.concat(enc);
exp = exp.concat(new ByteString("960201800000", HEX));
assert(r.equals(exp));
assert(isc.sendSequenceCounter.toString(16) == "FFFFFFFFFFFFFFFE");



// Case 4e CPRO		-> CLA'|INS|P1|P2|Lc'|TLplain|TLle|TLmac|00
var r = isc.wrap(apdu, Card.CPRO);

// Test result
var exp = new ByteString("0C102030000014810441424344970201808E08", HEX);
var mac = crypto.sign(kmac, Crypto.DES_MAC_EMV, new ByteString(
            "FFFFFFFFFFFFFFFF0C1020308000000081044142434497020180800000000000", HEX));
exp = exp.concat(mac).concat(new ByteString("0000", HEX));
assert(r.equals(exp));



// Case 4e CENC|CPRO	-> CLA'|INS|P1|P2|Lc'|TLenc|TLle|TLmac|00
var r = isc.wrap(apdu, Card.CENC|Card.CPRO);

// Test result
var exp = new ByteString("0C102030000019870901", HEX);
var enc = crypto.encrypt(kenc, Crypto.DES_CBC, 
            new ByteString("4142434480000000", HEX), iv);
exp = exp.concat(enc);
exp = exp.concat(new ByteString("970201808E08", HEX));
var macinp = new ByteString("00000000000000000C10203080000000870901", HEX);
macinp = macinp.concat(enc);
macinp = macinp.concat(new ByteString("97020180", HEX));
macinp = macinp.concat(new ByteString("80", HEX));
var mac = crypto.sign(kmac, Crypto.DES_MAC_EMV, macinp);
exp = exp.concat(mac).concat(new ByteString("0000", HEX));
assert(r.equals(exp));



// Special case: No MAC and no ENC
var ssc = new ByteString("FFFFFFFFFFFFFFF8", HEX);
isc.setMACSendSequenceCounter(ssc);

//Case 2e Command APDU CLA=00 INS=10 P1=20 P2=30 Le=000180
var apdu = new ByteString("00102030000000", HEX);

// Case 2e Plain		-> CLA'|INS|P1|P2|Lc'|TLle|00
var r = isc.wrap(apdu, 0);

// Test result
assert(r.toString(16) == "08102030000004960200000000");
assert(isc.sendSequenceCounter.toString(16) == "FFFFFFFFFFFFFFF8");




// Using AES with SSC default policy

var isc = new IsoSecureChannel(crypto);

var kencval = new ByteString("7CA110454A1A6E570131D9619DC1376E", HEX);
var kenc = new Key();
kenc.setComponent(Key.AES, kencval);

isc.setEncKey(kenc);


var kmacval = new ByteString("0131D9619DC1376E7CA110454A1A6E57", HEX);
var kmac = new Key();
kmac.setComponent(Key.AES, kmacval);

isc.setMacKey(kmac);

var ssc = new ByteString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6", HEX);
isc.setMACSendSequenceCounter(ssc);

var iv = new ByteString("11111111111111111111111111111111", HEX);
isc.setIV(iv);

//Case 4s Command APDU CLA=00 INS=10 P1=20 P2=30 Lc=04 Data=41424344 Le=80
var apdu = new ByteString("00102030044142434480", HEX);

//Case 4s CENC|CPRO	-> CLA'|INS|P1|P2|Lc'|TLenc|TLle|TLmac|00
var r = isc.wrap(apdu, Card.CENC|Card.CPRO);

//Test result
var exp = new ByteString("0C10203020871101", HEX);
var enc = crypto.encrypt(kenc, Crypto.AES_CBC, 
            new ByteString("41424344800000000000000000000000", HEX), iv);
exp = exp.concat(enc);
exp = exp.concat(new ByteString("9701808E08", HEX));
var macinp = new ByteString(
            "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70C" +
			"102030800000000000000000000000871101", HEX);
macinp = macinp.concat(enc);
macinp = macinp.concat(new ByteString("970180", HEX));
macinp = macinp.concat(new ByteString("80000000000000000000", HEX));
var mac = crypto.sign(kmac, Crypto.AES_CMAC, macinp);
exp = exp.concat(mac.left(8)).concat(new ByteString("00", HEX));

// print("Expected " + exp);
// print("Received " + r);

assert(r.equals(exp));



// Using AES with SSC_SYNC_POLICY

var isc = new IsoSecureChannel(crypto, IsoSecureChannel.SSC_SYNC_POLICY);

var kencval = new ByteString("7CA110454A1A6E570131D9619DC1376E", HEX);
var kenc = new Key();
kenc.setComponent(Key.AES, kencval);

isc.setEncKey(kenc);


var kmacval = new ByteString("0131D9619DC1376E7CA110454A1A6E57", HEX);
var kmac = new Key();
kmac.setComponent(Key.AES, kmacval);

isc.setMacKey(kmac);

var ssc = new ByteString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6", HEX);
isc.setMACSendSequenceCounter(ssc);
var nextssc = new ByteString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7", HEX);

var iv = new ByteString("00000000000000000000000000000000", HEX);


//Case 4s Command APDU CLA=00 INS=10 P1=20 P2=30 Lc=04 Data=41424344 Le=80
var apdu = new ByteString("00102030044142434480", HEX);

//Case 4s CENC|CPRO	-> CLA'|INS|P1|P2|Lc'|TLenc|TLle|TLmac|00
var r = isc.wrap(apdu, Card.CENC|Card.CPRO);

//Test result
var exp = new ByteString("0C10203020871101", HEX);
var enc = crypto.encrypt(kenc, Crypto.AES_CBC, new ByteString(
            "41424344800000000000000000000000", HEX), nextssc);
exp = exp.concat(enc);
exp = exp.concat(new ByteString("9701808E08", HEX));

var macinp = nextssc.concat(new ByteString(
            "0C102030800000000000000000000000871101", HEX));
macinp = macinp.concat(enc);
macinp = macinp.concat(new ByteString("970180", HEX));
macinp = macinp.concat(new ByteString("80000000000000000000", HEX));
var mac = crypto.sign(kmac, Crypto.AES_CMAC, macinp);
exp = exp.concat(mac.left(8)).concat(new ByteString("00", HEX));

// print("Expected " + exp);
// print("Received " + r);

assert(r.equals(exp));


//Using AES with SSC_SYNC_POLICY

var isc = new IsoSecureChannel(crypto, IsoSecureChannel.SSC_SYNC_ENC_POLICY);

var kencval = new ByteString("7CA110454A1A6E570131D9619DC1376E", HEX);
var kenc = new Key();
kenc.setComponent(Key.AES, kencval);

isc.setEncKey(kenc);


var kmacval = new ByteString("0131D9619DC1376E7CA110454A1A6E57", HEX);
var kmac = new Key();
kmac.setComponent(Key.AES, kmacval);

isc.setMacKey(kmac);

var ssc = new ByteString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6", HEX);
isc.setMACSendSequenceCounter(ssc);
var nextssc = new ByteString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7", HEX);

var iv = new ByteString("00000000000000000000000000000000", HEX);


//Case 4s Command APDU CLA=00 INS=10 P1=20 P2=30 Lc=04 Data=41424344 Le=80
var apdu = new ByteString("00102030044142434480", HEX);

//Case 4s CENC|CPRO	-> CLA'|INS|P1|P2|Lc'|TLenc|TLle|TLmac|00
var r = isc.wrap(apdu, Card.CENC|Card.CPRO);

//Test result
var exp = new ByteString("0C10203020871101", HEX);
var niv = crypto.encrypt(kenc, Crypto.AES_CBC, nextssc, iv);
var enc = crypto.encrypt(kenc, Crypto.AES_CBC, new ByteString(
            "41424344800000000000000000000000", HEX), niv);
exp = exp.concat(enc);
exp = exp.concat(new ByteString("9701808E08", HEX));

var macinp = nextssc.concat(new ByteString(
            "0C102030800000000000000000000000871101", HEX));
macinp = macinp.concat(enc);
macinp = macinp.concat(new ByteString("970180", HEX));
macinp = macinp.concat(new ByteString("80000000000000000000", HEX));
var mac = crypto.sign(kmac, Crypto.AES_CMAC, macinp);
exp = exp.concat(mac.left(8)).concat(new ByteString("00", HEX));

// print("Expected " + exp);
// print("Received " + r);

assert(r.equals(exp));



//Using AES with SSC default policy and odd instruction byte

var isc = new IsoSecureChannel(crypto);

var kencval = new ByteString("7CA110454A1A6E570131D9619DC1376E", HEX);
var kenc = new Key();
kenc.setComponent(Key.AES, kencval);

isc.setEncKey(kenc);


var kmacval = new ByteString("0131D9619DC1376E7CA110454A1A6E57", HEX);
var kmac = new Key();
kmac.setComponent(Key.AES, kmacval);

isc.setMacKey(kmac);

var ssc = new ByteString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6", HEX);
isc.setMACSendSequenceCounter(ssc);

var iv = new ByteString("11111111111111111111111111111111", HEX);
isc.setIV(iv);

//Case 4s Command APDU CLA=00 INS=11 P1=20 P2=30 Lc=04 Data=41424344 Le=80
var apdu = new ByteString("00112030048002123480", HEX);

//Case 4s CENC|CPRO	-> CLA'|INS|P1|P2|Lc'|TLenc|TLle|TLmac|00
var r = isc.wrap(apdu, Card.CENC|Card.CPRO);

//Test result
var exp = new ByteString("0C1120301F8510", HEX);
var enc = crypto.encrypt(kenc, Crypto.AES_CBC, new ByteString(
            "80021234800000000000000000000000", HEX), iv);
exp = exp.concat(enc);
exp = exp.concat(new ByteString("9701808E08", HEX));
var macinp = new ByteString(
            "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70C" +
            "1120308000000000000000000000008510", HEX);
macinp = macinp.concat(enc);
macinp = macinp.concat(new ByteString("970180", HEX));
macinp = macinp.concat(new ByteString("8000000000000000000000", HEX));
var mac = crypto.sign(kmac, Crypto.AES_CMAC, macinp);
exp = exp.concat(mac.left(8)).concat(new ByteString("00", HEX));

print("Expected " + exp);
print("Received " + r);

assert(r.equals(exp));

unwrap()

Prototype

ByteString unwrap(ByteString apduToUnwrap, Number usageQualifier)

Description

Unwrap a response-APDU from a secure messaging block and check the encryption and MAC.

Depending on the usageQualifier, no transformation (0), an decryption (Card.RENC), a MAC verification (Card.RPRO) or both (Card.RENC|Card.RPRO) is performed.

The APDU is transformed as defined in ISO 7816-4 and CWA 14890 (eSignK).

Arguments

Type Name Description
ByteString apduToUnwrap The response APDU to unwrap
Number usageQualifier A bitwise combination of Card.RPRO and Card.RENC.

Return

ByteString Unwrapped response APDU

Exceptions

Name Value Description
GPError GPError.ARGUMENTS_MISSING Too few arguments in call
GPError GPError.INVALID_ARGUMENTS Too many arguments in call
GPError GPError.INVALID_TYPE The type of the argument passed to the method is invalid
GPError GPError.INVALID_MECH The cryptographic operating is not supported by the selected crypto service
GPError GPError.CRYPTO_FAILED Either the MAC verification or data block decryption failed

Example


var isc = new IsoSecureChannel(crypto);

var kencval = new ByteString("7CA110454A1A6E570131D961" + 
                             "9DC1376E4A1A6E570131D961", HEX);
var kenc = new Key();
kenc.setComponent(Key.DES, kencval);
isc.setEncKey(kenc);

var kmacval = new ByteString("0131D9619DC1376E7CA11045" +
                             "4A1A6E579DC1376E7CA11045", HEX);
var kmac = new Key();
kmac.setComponent(Key.DES, kmacval);
isc.setMacKey(kmac);

var iv = new ByteString("1111111111111111", HEX);
isc.setIV(iv);

var ssc = new ByteString("0000000000000000", HEX);
isc.setMACSendSequenceCounter(ssc);

// SW1/SW2 only, Plain			-> SW1/SW2
// Prepare response from ICC
var apdu = new ByteString("9000", HEX);

var r = isc.unwrap(apdu, 0);

// Test result
assert(r.toString(16) == "9000");



// SW1/SW2 only, RPRO			-> TLmac|SW1/SW2
// Prepare response from ICC
var apdu = new ByteString("8E08", HEX);
var mac = crypto.sign(kmac, Crypto.DES_MAC_EMV, new ByteString(
            "00000000000000018000000000000000", HEX));
apdu = apdu.concat(mac);
apdu = apdu.concat(new ByteString("9000", HEX));

var r = isc.unwrap(apdu, Card.RPRO);

// Test result
assert(r.toString(16) == "9000");



// SW1/SW2 only, RPRO with SW1SW2	-> TLsw|TLmac|SW1/SW2
// Prepare response from ICC
var apdu = new ByteString("990212348E08", HEX);
var mac = crypto.sign(kmac, Crypto.DES_MAC_EMV, new ByteString(
            "00000000000000029902123480000000", HEX));
apdu = apdu.concat(mac);
apdu = apdu.concat(new ByteString("9000", HEX));

var r = isc.unwrap(apdu, Card.RPRO);

// Test result
assert(r.toString(16) == "1234");



// Data | SW1/SW2, Plain		-> TLplain|SW1/SW2
// Prepare response from ICC
var apdu = new ByteString("8004414243449000", HEX);

var r = isc.unwrap(apdu, 0);

// Test result
assert(r.toString(16) == "414243449000");



// Data | SW1/SW2, RENC			-> TLenc|SW1/SW2
// Prepare response from ICC
var apdu = new ByteString("860901", HEX);
var enc = crypto.encrypt(kenc, Crypto.DES_CBC, new ByteString(
            "4142434480000000", HEX), iv);
apdu = apdu.concat(enc);
apdu = apdu.concat(new ByteString("9000", HEX));

var r = isc.unwrap(apdu, Card.RENC);

// Test result
assert(r.toString(16) == "414243449000");
assert(isc.sendSequenceCounter.toString(16) == "0000000000000003");



// Data | SW1/SW2, RPRO			-> TLplain|TLmac|SW1/SW2
// Prepare response from ICC
var apdu = new ByteString("810441424344", HEX);
var macinp = new ByteString("0000000000000004", HEX);
macinp = macinp.concat(apdu);
var mac = crypto.sign(kmac, Crypto.DES_MAC_EMV, macinp.pad(Crypto.ISO9797_METHOD_2));
apdu = apdu.concat(new ByteString("8E08", HEX));
apdu = apdu.concat(mac);
apdu = apdu.concat(new ByteString("9000", HEX));

var r = isc.unwrap(apdu, Card.RPRO);

// Test result
assert(r.toString(16) == "414243449000");



// Data | SW1/SW2, RPRO with SW1/SW2	-> TLplain|TLsw|TLmac|SW1/SW2
// Prepare response from ICC
var apdu = new ByteString("81044142434499021234", HEX);
var macinp = new ByteString("0000000000000005", HEX);
macinp = macinp.concat(apdu);
var mac = crypto.sign(kmac, Crypto.DES_MAC_EMV, macinp.pad(Crypto.ISO9797_METHOD_2));
apdu = apdu.concat(new ByteString("8E08", HEX));
apdu = apdu.concat(mac);
apdu = apdu.concat(new ByteString("9000", HEX));

var r = isc.unwrap(apdu, Card.RPRO);

// Test result
assert(r.toString(16) == "414243441234");



// Data | SW1/SW2, RENC|RPRO		-> TLenc|TLmac|SW1/SW2
// Prepare response from ICC
var apdu = new ByteString("870901", HEX);
var enc = crypto.encrypt(kenc, Crypto.DES_CBC, new ByteString(
            "4142434480000000", HEX), iv);
apdu = apdu.concat(enc);
var macinp = new ByteString("0000000000000006", HEX);
macinp = macinp.concat(apdu);
var mac = crypto.sign(kmac, Crypto.DES_MAC_EMV, macinp.pad(Crypto.ISO9797_METHOD_2));
apdu = apdu.concat(new ByteString("8E08", HEX));
apdu = apdu.concat(mac);
apdu = apdu.concat(new ByteString("9000", HEX));

var r = isc.unwrap(apdu, Card.RPRO|Card.RENC);

// Test result
assert(r.toString(16) == "414243449000");



// Data | SW1/SW2, RENC|RPRO with SW1/SW2	-> TLenc|TLsw|TLmac|SW1/SW2
// Prepare response from ICC
var apdu = new ByteString("870901", HEX);
var enc = crypto.encrypt(kenc, Crypto.DES_CBC, new ByteString(
            "4142434480000000", HEX), iv);
apdu = apdu.concat(enc);
apdu = apdu.concat(new ByteString("99021234", HEX));
var macinp = new ByteString("0000000000000007", HEX);
macinp = macinp.concat(apdu);
var mac = crypto.sign(kmac, Crypto.DES_MAC_EMV, macinp.pad(Crypto.ISO9797_METHOD_2));
apdu = apdu.concat(new ByteString("8E08", HEX));
apdu = apdu.concat(mac);
apdu = apdu.concat(new ByteString("9000", HEX));

var r = isc.unwrap(apdu, Card.RPRO|Card.RENC);

// Test result
assert(r.toString(16) == "414243441234");



// Using AES with default policy

var isc = new IsoSecureChannel(crypto);

var kencval = new ByteString("7CA110454A1A6E570131D9619DC1376E", HEX);
var kenc = new Key();
kenc.setComponent(Key.AES, kencval);

isc.setEncKey(kenc);


var kmacval = new ByteString("0131D9619DC1376E7CA110454A1A6E57", HEX);
var kmac = new Key();
kmac.setComponent(Key.AES, kmacval);

isc.setMacKey(kmac);

var ssc = new ByteString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6", HEX);
isc.setMACSendSequenceCounter(ssc);

var iv = new ByteString("11111111111111111111111111111111", HEX);
isc.setIV(iv);


//Data | SW1/SW2, RENC|RPRO with SW1/SW2	-> TLenc|TLsw|TLmac|SW1/SW2
//Prepare response from ICC
var apdu = new ByteString("871101", HEX);
var enc = crypto.encrypt(kenc, Crypto.AES_CBC, new ByteString(
            "41424344800000000000000000000000", HEX), iv);
apdu = apdu.concat(enc);
apdu = apdu.concat(new ByteString("99021234", HEX));
var macinp = new ByteString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7", HEX);
macinp = macinp.concat(apdu);
macinp = macinp.concat(new ByteString("800000000000000000", HEX));
var mac = crypto.sign(kmac, Crypto.AES_CMAC, macinp);
apdu = apdu.concat(new ByteString("8E08", HEX));
apdu = apdu.concat(mac.left(8));
apdu = apdu.concat(new ByteString("9000", HEX));

// print("APDU " + apdu);
var r = isc.unwrap(apdu, Card.RPRO|Card.RENC);

// print("Received " + r);

//Test result
assert(r.toString(16) == "414243441234");



//Using AES with SSC_SYNC_POLICY

var isc = new IsoSecureChannel(crypto, IsoSecureChannel.SSC_SYNC_POLICY);

var kencval = new ByteString("7CA110454A1A6E570131D9619DC1376E", HEX);
var kenc = new Key();
kenc.setComponent(Key.AES, kencval);

isc.setEncKey(kenc);


var kmacval = new ByteString("0131D9619DC1376E7CA110454A1A6E57", HEX);
var kmac = new Key();
kmac.setComponent(Key.AES, kmacval);

isc.setMacKey(kmac);

var ssc = new ByteString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6", HEX);
isc.setMACSendSequenceCounter(ssc);
var nextssc = new ByteString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7", HEX);

var iv = new ByteString("00000000000000000000000000000000", HEX);


//Data | SW1/SW2, RENC|RPRO with SW1/SW2	-> TLenc|TLsw|TLmac|SW1/SW2
//Prepare response from ICC
var apdu = new ByteString("871101", HEX);
var enc = crypto.encrypt(kenc, Crypto.AES_CBC, new ByteString(
            "41424344800000000000000000000000", HEX), nextssc);
apdu = apdu.concat(enc);
apdu = apdu.concat(new ByteString("99021234", HEX));
var macinp = new ByteString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7", HEX);
macinp = macinp.concat(apdu);
macinp = macinp.concat(new ByteString("800000000000000000", HEX));
var mac = crypto.sign(kmac, Crypto.AES_CMAC, macinp);
apdu = apdu.concat(new ByteString("8E08", HEX));
apdu = apdu.concat(mac.left(8));
apdu = apdu.concat(new ByteString("9000", HEX));

// print("APDU " + apdu);
var r = isc.unwrap(apdu, Card.RPRO|Card.RENC);

// print("Received " + r);

//Test result
assert(r.toString(16) == "414243441234");



//Using AES with SSC_SYNC_ENC_POLICY

var isc = new IsoSecureChannel(crypto, IsoSecureChannel.SSC_SYNC_ENC_POLICY);

var kencval = new ByteString("7CA110454A1A6E570131D9619DC1376E", HEX);
var kenc = new Key();
kenc.setComponent(Key.AES, kencval);

isc.setEncKey(kenc);


var kmacval = new ByteString("0131D9619DC1376E7CA110454A1A6E57", HEX);
var kmac = new Key();
kmac.setComponent(Key.AES, kmacval);

isc.setMacKey(kmac);

var ssc = new ByteString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6", HEX);
isc.setMACSendSequenceCounter(ssc);
var nextssc = new ByteString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7", HEX);

var iv = new ByteString("00000000000000000000000000000000", HEX);


//Data | SW1/SW2, RENC|RPRO with SW1/SW2	-> TLenc|TLsw|TLmac|SW1/SW2
//Prepare response from ICC
var apdu = new ByteString("871101", HEX);
var niv = crypto.encrypt(kenc, Crypto.AES_CBC, nextssc, iv);
var enc = crypto.encrypt(kenc, Crypto.AES_CBC, new ByteString(
            "41424344800000000000000000000000", HEX), niv);
apdu = apdu.concat(enc);
apdu = apdu.concat(new ByteString("99021234", HEX));
var macinp = new ByteString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7", HEX);
macinp = macinp.concat(apdu);
macinp = macinp.concat(new ByteString("800000000000000000", HEX));
var mac = crypto.sign(kmac, Crypto.AES_CMAC, macinp);
apdu = apdu.concat(new ByteString("8E08", HEX));
apdu = apdu.concat(mac.left(8));
apdu = apdu.concat(new ByteString("9000", HEX));

// print("APDU " + apdu);
var r = isc.unwrap(apdu, Card.RPRO|Card.RENC);

// print("Received " + r);

//Test result
assert(r.toString(16) == "414243441234");



//Using AES with default policy and TLV data

var isc = new IsoSecureChannel(crypto);

var kencval = new ByteString("7CA110454A1A6E570131D9619DC1376E", HEX);
var kenc = new Key();
kenc.setComponent(Key.AES, kencval);

isc.setEncKey(kenc);


var kmacval = new ByteString("0131D9619DC1376E7CA110454A1A6E57", HEX);
var kmac = new Key();
kmac.setComponent(Key.AES, kmacval);

isc.setMacKey(kmac);

var ssc = new ByteString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6", HEX);
isc.setMACSendSequenceCounter(ssc);

var iv = new ByteString("11111111111111111111111111111111", HEX);
isc.setIV(iv);


//Data | SW1/SW2, RENC|RPRO with SW1/SW2	-> TLenc|TLsw|TLmac|SW1/SW2
//Prepare response from ICC
var apdu = new ByteString("8510", HEX);
var enc = crypto.encrypt(kenc, Crypto.AES_CBC, new ByteString(
            "80021234800000000000000000000000", HEX), iv);
apdu = apdu.concat(enc);
apdu = apdu.concat(new ByteString("99021234", HEX));
var macinp = new ByteString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7", HEX);
macinp = macinp.concat(apdu);
macinp = macinp.concat(new ByteString("80000000000000000000", HEX));
var mac = crypto.sign(kmac, Crypto.AES_CMAC, macinp);
apdu = apdu.concat(new ByteString("8E08", HEX));
apdu = apdu.concat(mac.left(8));
apdu = apdu.concat(new ByteString("9000", HEX));

print("APDU " + apdu);
var r = isc.unwrap(apdu, Card.RPRO|Card.RENC);

print("Received " + r);

//Test result
assert(r.toString(16) == "800212341234");



//Using AES with default policy and plain data

var isc = new IsoSecureChannel(crypto);

var kencval = new ByteString("7CA110454A1A6E570131D9619DC1376E", HEX);
var kenc = new Key();
kenc.setComponent(Key.AES, kencval);

isc.setEncKey(kenc);


var kmacval = new ByteString("0131D9619DC1376E7CA110454A1A6E57", HEX);
var kmac = new Key();
kmac.setComponent(Key.AES, kmacval);

isc.setMacKey(kmac);

var ssc = new ByteString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6", HEX);
isc.setMACSendSequenceCounter(ssc);

var iv = new ByteString("11111111111111111111111111111111", HEX);
isc.setIV(iv);


//Data | SW1/SW2, RENC|RPRO with SW1/SW2	-> TLenc|TLsw|TLmac|SW1/SW2
//Prepare response from ICC
var apdu = new ByteString("B304", HEX);
var enc = crypto.encrypt(kenc, Crypto.AES_CBC, new ByteString(
            "80021234800000000000000000000000", HEX), iv);
apdu = apdu.concat(new ByteString("80021234", HEX));
apdu = apdu.concat(new ByteString("99021234", HEX));
var macinp = new ByteString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7", HEX);
macinp = macinp.concat(apdu);
macinp = macinp.concat(new ByteString("800000000000", HEX));
var mac = crypto.sign(kmac, Crypto.AES_CMAC, macinp);
apdu = apdu.concat(new ByteString("8E08", HEX));
apdu = apdu.concat(mac.left(8));
apdu = apdu.concat(new ByteString("9000", HEX));

print("APDU " + apdu);
var r = isc.unwrap(apdu, Card.RPRO);

print("Received " + r);

//Test result
assert(r.toString(16) == "800212341234");



setCRT()

Prototype

void setCRT(ByteString crt)

Description

Set a cryptographic reference template to be included in the body of the command APDU.

The CRT is included in the MAC if the tag is odd.

Arguments

Type Name Description
ByteString crt The cryptographic reference template or null

Return

void The method does not return a value

Exceptions

Name Value Description
GPError GPError.ARGUMENTS_MISSING Too few arguments in call
GPError GPError.INVALID_ARGUMENTS Too many arguments in call
GPError GPError.INVALID_TYPE The argument must be of type ByteString

Example


var isc = new IsoSecureChannel(crypto);

var kencval = new ByteString("7CA110454A1A6E570131D961" +
                             "9DC1376E4A1A6E570131D961", HEX);
var kenc = new Key();
kenc.setComponent(Key.DES, kencval);
isc.setEncKey(kenc);

var kmacval = new ByteString("0131D9619DC1376E7CA11045" +
                             "4A1A6E579DC1376E7CA11045", HEX);
var kmac = new Key();
kmac.setComponent(Key.DES, kmacval);
isc.setMacKey(kmac);

var iv = new ByteString("1111111111111111", HEX);
isc.setIV(iv);

var crt = new ByteString("B803830103", HEX);
isc.setCRT(crt);

var ssc = new ByteString("FFFFFFFFFFFFFFFD", HEX);
isc.setMACSendSequenceCounter(ssc);

//Case 4s Command APDU CLA=00 INS=10 P1=20 P2=30 Lc=04 Data=41424344 Le=80
var apdu = new ByteString("00102030044142434480", HEX);

// Case 4s Plain		-> CLA'|INS|P1|P2|Lc'|TLplain|TLle|00
var r = isc.wrap(apdu, 0);

// Test result
assert(r.toString(16) == "081020300EB80383010380044142434496018000");
assert(isc.sendSequenceCounter.toString(16) == "FFFFFFFFFFFFFFFD");



// Case 4s CENC		-> CLA'|INS|P1|P2|Lc'|TLenc|TLle|00
var r = isc.wrap(apdu, Card.CENC);

// Test result
var exp = new ByteString("0810203013B803830103860901", HEX);
var enc = crypto.encrypt(kenc, Crypto.DES_CBC, new ByteString(
            "4142434480000000", HEX), iv);
exp = exp.concat(enc);
exp = exp.concat(new ByteString("96018000", HEX));
assert(r.equals(exp));
assert(isc.sendSequenceCounter.toString(16) == "FFFFFFFFFFFFFFFE");



// Case 4s CPRO		-> CLA'|INS|P1|P2|Lc'|TLplain|TLle|TLmac|00
var r = isc.wrap(apdu, Card.CPRO);

// Test result
var exp = new ByteString("0C10203018B8038301038104414243449701808E08", HEX);
var mac = crypto.sign(kmac, Crypto.DES_MAC_EMV, new ByteString(
            "FFFFFFFFFFFFFFFF0C10203080000000" +
            "81044142434497018080000000000000", HEX));
exp = exp.concat(mac).concat(new ByteString("00", HEX));
assert(r.equals(exp));


var crt = new ByteString("B903830103", HEX);
isc.setCRT(crt);

// Case 4s CENC|CPRO	-> CLA'|INS|P1|P2|Lc'|TLenc|TLle|TLmac|00
var r = isc.wrap(apdu, Card.CENC|Card.CPRO);

// Test result
var exp = new ByteString("0C1020301DB903830103870901", HEX);
var enc = crypto.encrypt(kenc, Crypto.DES_CBC, new ByteString(
            "4142434480000000", HEX), iv);
exp = exp.concat(enc);
exp = exp.concat(new ByteString("9701808E08", HEX));
var macinp = new ByteString("00000000000000000C10203080000000B903830103870901", HEX);
macinp = macinp.concat(enc);
macinp = macinp.concat(new ByteString("970180", HEX));
macinp = macinp.concat(new ByteString("8000000000", HEX));
var mac = crypto.sign(kmac, Crypto.DES_MAC_EMV, macinp);
exp = exp.concat(mac).concat(new ByteString("00", HEX));

// print("Expected " + exp);
// print("Received " + r);

assert(r.equals(exp));