Java Code Examples for javacard.framework.ISO7816#OFFSET_CDATA
The following examples show how to use
javacard.framework.ISO7816#OFFSET_CDATA .
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: LedgerWalletApplet.java From ledger-javacard with GNU Affero General Public License v3.0 | 6 votes |
private static void handleAdmSetKeycardSeed(APDU apdu, boolean airgap) throws ISOException { byte[] buffer = apdu.getBuffer(); short offset = ISO7816.OFFSET_CDATA; byte keyLength; apdu.setIncomingAndReceive(); if ((setup == TC.TRUE) || (setup != TC.FALSE)) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } if (buffer[ISO7816.OFFSET_LC] != (byte)(KEYCARD_KEY_LENGTH + 1)) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } if ((buffer[offset] == (byte)0) || (buffer[offset] > TC.MAX_KEYCARD_DIGIT_ADDRESS)) { ISOException.throwIt(ISO7816.SW_WRONG_DATA); } if (!airgap) { Keycard.setIssuer(buffer[offset], buffer, (short)(offset + 1)); } else { Crypto.initCipherAES(pairingKey, false); Crypto.blobEncryptDecryptAES.doFinal(buffer, (short)(offset + 1), (short)16, scratch256, (short)0); Keycard.setIssuer(buffer[offset], scratch256, (short)0); } }
Example 2
Source File: GidsPINManager.java From GidsApplet with GNU General Public License v3.0 | 5 votes |
/** * \brief Process the general authentication process */ public void processGeneralAuthenticate(APDU apdu) { byte[] buf = apdu.getBuffer(); byte p1 = buf[ISO7816.OFFSET_P1]; byte p2 = buf[ISO7816.OFFSET_P2]; short lc; if(isInInitializationMode) { ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); } if(p1 != (byte) 0x00 || p2 != (byte) 0x00 ) { ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); } // Bytes received must be Lc. lc = apdu.setIncomingAndReceive(); short innerPos = 0, innerLen = 0; if (buf[ISO7816.OFFSET_CDATA] != (byte) 0x7C) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } try { innerLen = UtilTLV.decodeLengthField(buf, (short) (ISO7816.OFFSET_CDATA+1)); innerPos = (short) (ISO7816.OFFSET_CDATA + 1 + UtilTLV.getLengthFieldLength(buf, (short) (ISO7816.OFFSET_CDATA+1))); } catch (InvalidArgumentsException e1) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } // inner functions never return if their input tag is found if (CheckForExternalChallenge(apdu, buf, innerPos, innerLen)) { return; } if (CheckForChallengeResponse(apdu, buf, innerPos, innerLen)) { return; } ISOException.throwIt(ISO7816.SW_DATA_INVALID); }
Example 3
Source File: CardEdge.java From SatochipApplet with GNU Affero General Public License v3.0 | 5 votes |
/** * This function creates a PIN with parameters specified by the P1, P2 and DATA * values. P2 specifies the maximum number of consecutive unsuccessful * verifications before the PIN blocks. PIN can be created only if one of the logged identities * allows it. * * ins: 0x40 * p1: PIN number (0x00-0x07) * p2: max attempt number * data: [PIN_size(1b) | PIN | UBLK_size(1b) | UBLK] * return: none */ private short CreatePIN(APDU apdu, byte[] buffer) { // check that PIN[0] has been entered previously if (!pins[0].isValidated()) ISOException.throwIt(SW_UNAUTHORIZED); byte pin_nb = buffer[ISO7816.OFFSET_P1]; byte num_tries = buffer[ISO7816.OFFSET_P2]; if ((pin_nb < 0) || (pin_nb >= MAX_NUM_PINS) || (pins[pin_nb] != null)) ISOException.throwIt(SW_INCORRECT_P1); /* Allow pin lengths > 127 (useful at all ?) */ short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]); // At least 1 character for PIN and 1 for unblock code (+ lengths) if (bytesLeft < 4) ISOException.throwIt(SW_INVALID_PARAMETER); byte pin_size = buffer[ISO7816.OFFSET_CDATA]; if (bytesLeft < (short) (1 + pin_size + 1)) ISOException.throwIt(SW_INVALID_PARAMETER); if (!CheckPINPolicy(buffer, (short) (ISO7816.OFFSET_CDATA + 1), pin_size)) ISOException.throwIt(SW_INVALID_PARAMETER); byte ucode_size = buffer[(short) (ISO7816.OFFSET_CDATA + 1 + pin_size)]; if (bytesLeft != (short) (1 + pin_size + 1 + ucode_size)) ISOException.throwIt(SW_INVALID_PARAMETER); if (!CheckPINPolicy(buffer, (short) (ISO7816.OFFSET_CDATA + 1 + pin_size + 1), ucode_size)) ISOException.throwIt(SW_INVALID_PARAMETER); pins[pin_nb] = new OwnerPIN(num_tries, PIN_MAX_SIZE); pins[pin_nb].update(buffer, (short) (ISO7816.OFFSET_CDATA + 1), pin_size); ublk_pins[pin_nb] = new OwnerPIN((byte) 3, PIN_MAX_SIZE); // Recycle variable pin_size pin_size = (byte) (ISO7816.OFFSET_CDATA + 1 + pin_size + 1); ublk_pins[pin_nb].update(buffer, pin_size, ucode_size); return (short)0; }
Example 4
Source File: LedgerWalletApplet.java From ledger-javacard with GNU Affero General Public License v3.0 | 5 votes |
private static void handleHashSignDerive(APDU apdu, boolean checkStage) throws ISOException { byte[] buffer = apdu.getBuffer(); short offset = ISO7816.OFFSET_CDATA; byte i; apdu.setIncomingAndReceive(); if (checkStage) { checkInterfaceConsistency(); if (TC.ctx[TC.TX_B_TRANSACTION_STATE] != Transaction.STATE_SIGN_READY) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } } byte derivationSize = buffer[offset++]; if (derivationSize > MAX_DERIVATION_PATH) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } Crypto.initCipher(chipKey, false); Crypto.blobEncryptDecrypt.doFinal(masterDerived, (short)0, (short)DEFAULT_SEED_LENGTH, scratch256, (short)0); i = Bip32Cache.copyPrivateBest(buffer, (short)(ISO7816.OFFSET_CDATA + 1), derivationSize, scratch256, (short)0); offset += (short)(i * 4); for (; i<derivationSize; i++) { Util.arrayCopyNonAtomic(buffer, offset, scratch256, Bip32.OFFSET_DERIVATION_INDEX, (short)4); if ((proprietaryAPI == null) && ((scratch256[Bip32.OFFSET_DERIVATION_INDEX] & (byte)0x80) == 0)) { if (!Bip32Cache.setPublicIndex(buffer, (short)(ISO7816.OFFSET_CDATA + 1), i)) { ISOException.throwIt(SW_PUBLIC_POINT_NOT_AVAILABLE); } } if (!Bip32.derive(buffer)) { ISOException.throwIt(ISO7816.SW_WRONG_DATA); } Bip32Cache.storePrivate(buffer, (short)(ISO7816.OFFSET_CDATA + 1), (byte)(i + 1), scratch256); offset += (short)4; } }
Example 5
Source File: CardEdge.java From SatochipApplet with GNU Affero General Public License v3.0 | 5 votes |
/** * This function allows to set the 2FA key and enable 2FA. * Once activated, 2FA can only be deactivated when the seed is reset. * * ins: 0x79 * p1: 0x00 * p2: 0x00 * data: [hmacsha1_key(20b) | amount_limit(8b)] * return: (none) */ private short set2FAKey(APDU apdu, byte[] buffer){ // check that PIN[0] has been entered previously if (!pins[0].isValidated()) ISOException.throwIt(SW_UNAUTHORIZED); // cannot modify an existing 2FA! if (needs_2FA) ISOException.throwIt(SW_2FA_INITIALIZED_KEY); //check input length short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]); if (bytesLeft < (short)(20+8)) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); if (!done_once_2FA){ data2FA= new byte[OFFSET_2FA_SIZE]; randomData = RandomData.getInstance(RandomData.ALG_SECURE_RANDOM); aes128_cbc= Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false); key_2FA= (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_128, false); done_once_2FA= true; } short offset= ISO7816.OFFSET_CDATA; Util.arrayCopyNonAtomic(buffer, offset, data2FA, OFFSET_2FA_HMACKEY, (short)20); offset+=(short)20; Util.arrayCopyNonAtomic(buffer, offset, data2FA, OFFSET_2FA_LIMIT, (short)8); offset+=(short)8; // hmac derivation for id_2FA & key_2FA HmacSha160.computeHmacSha160(data2FA, OFFSET_2FA_HMACKEY, (short)20, CST_2FA, (short)0, (short)6, data2FA, OFFSET_2FA_ID); HmacSha160.computeHmacSha160(data2FA, OFFSET_2FA_HMACKEY, (short)20, CST_2FA, (short)6, (short)7, recvBuffer, (short)0); key_2FA.setKey(recvBuffer,(short)0); // AES-128: 16-bytes key!! needs_2FA= true; return (short)0; }
Example 6
Source File: LedgerWalletApplet.java From ledger-javacard with GNU Affero General Public License v3.0 | 5 votes |
private static void handleGetHalfPublicKey(APDU apdu) throws ISOException { byte[] buffer = apdu.getBuffer(); apdu.setIncomingAndReceive(); short offset = ISO7816.OFFSET_CDATA; byte derivationSize = buffer[offset++]; byte i; if (Crypto.keyAgreement == null) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } if (derivationSize > MAX_DERIVATION_PATH) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } Crypto.initCipher(chipKey, false); Crypto.blobEncryptDecrypt.doFinal(masterDerived, (short)0, (short)DEFAULT_SEED_LENGTH, scratch256, (short)0); i = Bip32Cache.copyPrivateBest(buffer, (short)(ISO7816.OFFSET_CDATA + 1), derivationSize, scratch256, (short)0); for (; i<derivationSize; i++) { Util.arrayCopyNonAtomic(buffer, (short)(offset + 4 * i), scratch256, Bip32.OFFSET_DERIVATION_INDEX, (short)4); if ((proprietaryAPI == null) && ((scratch256[Bip32.OFFSET_DERIVATION_INDEX] & (byte)0x80) == 0)) { if (!Bip32Cache.setPublicIndex(buffer, (short)(ISO7816.OFFSET_CDATA + 1), i)) { ISOException.throwIt(SW_PUBLIC_POINT_NOT_AVAILABLE); } } if (!Bip32.derive(buffer)) { ISOException.throwIt(ISO7816.SW_WRONG_DATA); } Bip32Cache.storePrivate(buffer, (short)(ISO7816.OFFSET_CDATA + 1), (byte)(i + 1), scratch256); } Crypto.initTransientPrivate(scratch256, (short)0); Crypto.keyAgreement.init(Crypto.transientPrivate); Crypto.keyAgreement.generateSecret(Secp256k1.SECP256K1_G, (short)0, (short)Secp256k1.SECP256K1_G.length, scratch256, (short)32); offset = 0; Crypto.random.generateData(buffer, (short)offset, (short)32); offset += 32; Util.arrayCopyNonAtomic(scratch256, (short)32, buffer, offset, (short)32); offset += 32; signTransientPrivate(scratch256, (short)0, buffer, (short)0, buffer, offset); offset += buffer[(short)(offset + 1)] + 2; Crypto.digestScratch.doFinal(buffer, (short)0, (short)32, buffer, (short)0); apdu.setOutgoingAndSend((short)0, offset); }
Example 7
Source File: LedgerWalletApplet.java From ledger-javacard with GNU Affero General Public License v3.0 | 5 votes |
private static void handleStorePublicKey(APDU apdu) throws ISOException { byte[] buffer = apdu.getBuffer(); apdu.setIncomingAndReceive(); short offset = ISO7816.OFFSET_CDATA; byte derivationSize = buffer[offset++]; byte i; if (Crypto.keyAgreement == null) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } if (derivationSize > MAX_DERIVATION_PATH) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } Crypto.initCipher(chipKey, false); Crypto.blobEncryptDecrypt.doFinal(masterDerived, (short)0, (short)DEFAULT_SEED_LENGTH, scratch256, (short)0); i = Bip32Cache.copyPrivateBest(buffer, (short)(ISO7816.OFFSET_CDATA + 1), derivationSize, scratch256, (short)0); for (; i<derivationSize; i++) { Util.arrayCopyNonAtomic(buffer, (short)(offset + 4 * i), scratch256, Bip32.OFFSET_DERIVATION_INDEX, (short)4); if ((proprietaryAPI == null) && ((scratch256[Bip32.OFFSET_DERIVATION_INDEX] & (byte)0x80) == 0)) { if (!Bip32Cache.setPublicIndex(buffer, (short)(ISO7816.OFFSET_CDATA + 1), i)) { ISOException.throwIt(SW_PUBLIC_POINT_NOT_AVAILABLE); } } if (!Bip32.derive(buffer)) { ISOException.throwIt(ISO7816.SW_WRONG_DATA); } Bip32Cache.storePrivate(buffer, (short)(ISO7816.OFFSET_CDATA + 1), (byte)(i + 1), scratch256); } offset += (short)(derivationSize * 4); Crypto.random.generateData(scratch256, (short)32, (short)32); signTransientPrivate(scratch256, (short)0, scratch256, (short)32, scratch256, (short)64); if (Crypto.verifyPublic(buffer, offset, scratch256, (short)32, scratch256, (short)64)) { Bip32Cache.storePublic(buffer, (short)(ISO7816.OFFSET_CDATA + 1), derivationSize, buffer, offset); } else { ISOException.throwIt(ISO7816.SW_WRONG_DATA); } }
Example 8
Source File: LedgerWalletApplet.java From ledger-javacard with GNU Affero General Public License v3.0 | 5 votes |
private static void handleHasCachedPublicKey(APDU apdu) throws ISOException { byte[] buffer = apdu.getBuffer(); apdu.setIncomingAndReceive(); short offset = ISO7816.OFFSET_CDATA; byte derivationSize = buffer[offset++]; if (derivationSize > MAX_DERIVATION_PATH) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } boolean result = Bip32Cache.hasPublic(buffer, offset, derivationSize); buffer[0] = (result ? (byte)0x01 : (byte)0x00); apdu.setOutgoingAndSend((short)0, (short)1); }
Example 9
Source File: CardEdge.java From SatochipApplet with GNU Affero General Public License v3.0 | 4 votes |
/** * This function allows to initiate a Secure Channel * * ins: 0x81 * p1: 0x00 * p2: 0x00 * data: [client-pubkey(65b)] * return: [coordx_size(2b) | authentikey-coordx | sig_size(2b) | self-sig | sig2_size(optional) | authentikey-sig(optional)] */ private short InitiateSecureChannel(APDU apdu, byte[] buffer){ // get client pubkey short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]); if (bytesLeft < (short)65) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); if (buffer[ISO7816.OFFSET_CDATA] != (byte)0x04) ISOException.throwIt(SW_INVALID_PARAMETER); // generate a new ephemeral key sc_ephemeralkey.clearKey(); Secp256k1.setCommonCurveParameters(sc_ephemeralkey);// keep public params! randomData.generateData(recvBuffer, (short)0, BIP32_KEY_SIZE); sc_ephemeralkey.setS(recvBuffer, (short)0, BIP32_KEY_SIZE); //random value first // compute the shared secret... keyAgreement.init(sc_ephemeralkey); short coordx_size= (short)32; keyAgreement.generateSecret(buffer, ISO7816.OFFSET_CDATA, (short) 65, recvBuffer, (short)0); //pubkey in uncompressed form // derive sc_sessionkey & sc_mackey HmacSha160.computeHmacSha160(recvBuffer, (short)1, (short)32, CST_SC, (short)6, (short)6, recvBuffer, (short)33); Util.arrayCopyNonAtomic(recvBuffer, (short)33, sc_buffer, OFFSET_SC_MACKEY, SIZE_SC_MACKEY); HmacSha160.computeHmacSha160(recvBuffer, (short)1, (short)32, CST_SC, (short)0, (short)6, recvBuffer, (short)33); sc_sessionkey.setKey(recvBuffer,(short)33); // AES-128: 16-bytes key!! // //alternatively: derive session_key (sha256 of coordx) // sha256.reset(); // sha256.doFinal(recvBuffer, (short)1, (short)32, recvBuffer, (short) 0); // sc_sessionkey.setKey(recvBuffer,(short)0); // AES-128: 16-bytes key!! // //derive mac_key // sha256.reset(); // sha256.doFinal(recvBuffer, (short)0, (short)32, sc_mackey, (short) 0); //reset IV counter Util.arrayFillNonAtomic(sc_buffer, OFFSET_SC_IV, SIZE_SC_IV, (byte) 0); // self signed ephemeral pubkey keyAgreement.generateSecret(Secp256k1.SECP256K1, Secp256k1.OFFSET_SECP256K1_G, (short) 65, buffer, (short)1); //pubkey in uncompressed form Util.setShort(buffer, (short)0, coordx_size); sigECDSA.init(sc_ephemeralkey, Signature.MODE_SIGN); short sign_size= sigECDSA.sign(buffer, (short)0, (short)(coordx_size+2), buffer, (short)(coordx_size+4)); Util.setShort(buffer, (short)(coordx_size+2), sign_size); // hash signed by authentikey if seed is initialized short offset= (short)(2+coordx_size+2+sign_size); if (bip32_seeded){ sigECDSA.init(bip32_authentikey, Signature.MODE_SIGN); short sign2_size= sigECDSA.sign(buffer, (short)0, offset, buffer, (short)(offset+2)); Util.setShort(buffer, offset, sign2_size); offset+=(short)(2+sign2_size); }else{ Util.setShort(buffer, offset, (short)0); offset+=(short)2; } initialized_secure_channel= true; // return x-coordinate of public key+signature // the client can recover full public-key from the signature or // by guessing the compression value () and verifying the signature... // buffer= [coordx_size(2) | coordx | sigsize(2) | sig | sig2_size(optional) | sig2(optional)] return offset; }
Example 10
Source File: LedgerWalletApplet.java From ledger-javacard with GNU Affero General Public License v3.0 | 4 votes |
private static void handleSignMessage(APDU apdu) throws ISOException { byte[] buffer = apdu.getBuffer(); short offset = ISO7816.OFFSET_CDATA; if (buffer[ISO7816.OFFSET_P1] == P1_PREPARE_MESSAGE) { byte derivationSize = buffer[offset++]; boolean addressVerified = false; if (Util.arrayCompare(buffer, offset, SLIP13_HEAD, (short)0, (short)SLIP13_HEAD.length) == (short)0) { addressVerified = true; } else { for (byte i=0; i<derivationSize; i++) { if ((Util.arrayCompare(buffer, (short)(offset + 2), BITID_DERIVE, (short)0, (short)BITID_DERIVE.length) == (short)0) || (Util.arrayCompare(buffer, (short)(offset + 2), BITID_DERIVE_MULTIPLE, (short)0, (short)BITID_DERIVE_MULTIPLE.length) == (short)0)) { addressVerified = true; break; } offset += 4; } } if (!addressVerified) { ISOException.throwIt(ISO7816.SW_WRONG_DATA); } offset = (short)(ISO7816.OFFSET_CDATA + 1 + 4 * derivationSize); short messageLength = (short)(buffer[offset++] & 0xff); Crypto.digestFull.reset(); Crypto.digestFull.update(SIGNMAGIC, (short)0, (short)SIGNMAGIC.length); scratch256[(short)100] = (byte)messageLength; Crypto.digestFull.update(scratch256, (short)100, (short)1); Crypto.digestFull.doFinal(buffer, offset, messageLength, scratch256, (short)32); signTransientPrivate(scratch256, (short)0, scratch256, (short)32, scratch256, (short)100); Util.arrayFillNonAtomic(scratch256, (short)0, (short)64, (byte)0x00); buffer[(short)0] = (byte)0x00; TC.ctx[TC.TX_B_MESSAGE_SIGN_READY] = (byte)0x01; apdu.setOutgoingAndSend((short)0, (short)1); } else if (buffer[ISO7816.OFFSET_P1] == P1_SIGN_MESSAGE) { if (TC.ctx[TC.TX_B_MESSAGE_SIGN_READY] != (byte)0x01) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } TC.ctx[TC.TX_B_MESSAGE_SIGN_READY] = (byte)0x00; short signatureSize = (short)((short)(scratch256[(short)101] & 0xff) + 2); Util.arrayCopyNonAtomic(scratch256, (short)100, buffer, (short)0, signatureSize); apdu.setOutgoingAndSend((short)0, signatureSize); } else { ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); } }
Example 11
Source File: LedgerWalletApplet.java From ledger-javacard with GNU Affero General Public License v3.0 | 4 votes |
private static void handleHashSign(APDU apdu) throws ISOException { byte[] buffer = apdu.getBuffer(); short offset = ISO7816.OFFSET_CDATA; byte i; byte derivationSize = buffer[offset++]; offset += (short)(derivationSize * 4); short authorizationLength = (short)(buffer[offset++] & 0xff); if (TC.ctxP[TC.P_TX_Z_CONSUME_P2SH] == TC.FALSE) { boolean verified = false; writeIdleText(); if (TC.ctxP[TC.P_TX_Z_USE_KEYCARD] == TC.TRUE) { Util.arrayCopyNonAtomic(TC.ctxP, TC.P_TX_A_OUTPUT_ADDRESS, scratch256, (short)32, (short)(TC.SIZEOF_RIPEMD + 1)); Crypto.digestScratch.doFinal(scratch256, (short)32, (short)(TC.SIZEOF_RIPEMD + 1), scratch256, (short)(32 + TC.SIZEOF_RIPEMD + 1)); Crypto.digestScratch.doFinal(scratch256, (short)(32 + TC.SIZEOF_RIPEMD + 1), TC.SIZEOF_SHA256, scratch256, (short)(32 + TC.SIZEOF_RIPEMD + 1)); short addressOffset = Base58.encode(scratch256, (short)32, (short)(TC.SIZEOF_RIPEMD + 1 + 4), scratch256, (short)100, scratch256, (short)150); verified = Keycard.check(scratch256, (short)100, (byte)(addressOffset - 100), buffer, offset, (byte)authorizationLength, TC.ctxP, TC.P_TX_A_KEYCARD_INDEXES, scratch256, (short)150); } if (!verified) { if (!transactionPin.check(buffer, offset, (byte)authorizationLength)) { ISOException.throwIt(ISO7816.SW_WRONG_DATA); } } } else if (TC.ctxP[TC.P_TX_Z_CONSUME_P2SH] != TC.TRUE) { ISOException.throwIt(ISO7816.SW_WRONG_DATA); } offset += authorizationLength; Uint32Helper.swap(scratch256, (short)100, buffer, offset); offset += 4; byte sigHashType = buffer[offset++]; Uint32Helper.clear(scratch256, (short)104); scratch256[(short)104] = sigHashType; Crypto.digestFull.doFinal(scratch256, (short)100, (short)8, scratch256, (short)100); signTransientPrivate(scratch256, (short)0, scratch256, (short)100, buffer, (short)0); short signatureSize = (short)((short)(buffer[1] & 0xff) + 2); buffer[signatureSize] = sigHashType; TC.clear(); apdu.setOutgoingAndSend((short)0, (short)(signatureSize + 1)); }
Example 12
Source File: LedgerWalletApplet.java From ledger-javacard with GNU Affero General Public License v3.0 | 4 votes |
private static void handleGetWalletPublicKey(APDU apdu) throws ISOException { byte[] buffer = apdu.getBuffer(); short offset = ISO7816.OFFSET_CDATA; byte derivationSize = buffer[offset++]; byte i; if (derivationSize > MAX_DERIVATION_PATH) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } Crypto.initCipher(chipKey, false); Crypto.blobEncryptDecrypt.doFinal(masterDerived, (short)0, (short)DEFAULT_SEED_LENGTH, scratch256, (short)0); i = Bip32Cache.copyPrivateBest(buffer, (short)(ISO7816.OFFSET_CDATA + 1), derivationSize, scratch256, (short)0); for (; i<derivationSize; i++) { Util.arrayCopyNonAtomic(buffer, (short)(offset + 4 * i), scratch256, Bip32.OFFSET_DERIVATION_INDEX, (short)4); if ((proprietaryAPI == null) && ((scratch256[Bip32.OFFSET_DERIVATION_INDEX] & (byte)0x80) == 0)) { if (!Bip32Cache.setPublicIndex(buffer, (short)(ISO7816.OFFSET_CDATA + 1), i)) { ISOException.throwIt(SW_PUBLIC_POINT_NOT_AVAILABLE); } } if (!Bip32.derive(buffer)) { ISOException.throwIt(ISO7816.SW_WRONG_DATA); } Bip32Cache.storePrivate(buffer, (short)(ISO7816.OFFSET_CDATA + 1), (byte)(i + 1), scratch256); } if (proprietaryAPI == null) { if (!Bip32Cache.setPublicIndex(buffer, offset, derivationSize)) { ISOException.throwIt(SW_PUBLIC_POINT_NOT_AVAILABLE); } } offset = 0; buffer[offset++] = (short)65; if (proprietaryAPI == null) { Bip32Cache.copyLastPublic(buffer, offset); } else { proprietaryAPI.getUncompressedPublicPoint(scratch256, (short)0, buffer, offset); } Util.arrayCopyNonAtomic(scratch256, (short)32, buffer, (short)200, (short)32); Util.arrayCopyNonAtomic(buffer, offset, scratch256, (short)0, (short)65); AddressUtils.compressPublicKey(scratch256, (short)0); offset += (short)65; buffer[offset] = (byte)(publicKeyToAddress(buffer, (short)(offset + 1)) - (short)(offset + 1)); offset += (short)(buffer[offset] + 1); Util.arrayCopyNonAtomic(buffer, (short)200, buffer, offset, (short)32); offset += 32; apdu.setOutgoingAndSend((short)0, offset); }
Example 13
Source File: CardEdge.java From SatochipApplet with GNU Affero General Public License v3.0 | 4 votes |
/** * This function allows to decrypt a secure channel message * * ins: 0x82 * * p1: 0x00 (RFU) * p2: 0x00 (RFU) * data: [IV(16b) | data_size(2b) | encrypted_command | mac_size(2b) | mac] * * return: [decrypted command] * */ private short ProcessSecureChannel(APDU apdu, byte[] buffer){ short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]); short offset = ISO7816.OFFSET_CDATA; if (!initialized_secure_channel){ ISOException.throwIt(SW_SECURE_CHANNEL_UNINITIALIZED); } // check hmac if (bytesLeft<18) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); short sizein = Util.getShort(buffer, (short) (offset+SIZE_SC_IV)); if (bytesLeft<(short)(SIZE_SC_IV+2+sizein+2)) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); short sizemac= Util.getShort(buffer, (short) (offset+SIZE_SC_IV+2+sizein)); if (sizemac != (short)20) ISOException.throwIt(SW_SECURE_CHANNEL_WRONG_MAC); if (bytesLeft<(short)(SIZE_SC_IV+2+sizein+2+sizemac)) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); HmacSha160.computeHmacSha160(sc_buffer, OFFSET_SC_MACKEY, SIZE_SC_MACKEY, buffer, offset, (short)(SIZE_SC_IV+2+sizein), recvBuffer, (short)0); if ( Util.arrayCompare(recvBuffer, (short)0, buffer, (short)(offset+SIZE_SC_IV+2+sizein+2), (short)20) != (byte)0 ) ISOException.throwIt(SW_SECURE_CHANNEL_WRONG_MAC); // process IV // IV received from client should be odd and strictly greater than locally saved IV // IV should be random (the 12 first bytes), never reused (the last 4 bytes counter) and different for send and receive if ((buffer[(short)(offset+SIZE_SC_IV-(short)1)] & (byte)0x01)==0x00)// should be odd ISOException.throwIt(SW_SECURE_CHANNEL_WRONG_IV); if ( !Biginteger.lessThan(sc_buffer, OFFSET_SC_IV_COUNTER, buffer, (short)(offset+SIZE_SC_IV_RANDOM), SIZE_SC_IV_COUNTER ) ) //and greater than local IV ISOException.throwIt(SW_SECURE_CHANNEL_WRONG_IV); // update local IV Util.arrayCopy(buffer, (short)(offset+SIZE_SC_IV_RANDOM), sc_buffer, OFFSET_SC_IV_COUNTER, SIZE_SC_IV_COUNTER); Biginteger.add1_carry(sc_buffer, OFFSET_SC_IV_COUNTER, SIZE_SC_IV_COUNTER); randomData.generateData(sc_buffer, OFFSET_SC_IV_RANDOM, SIZE_SC_IV_RANDOM); sc_aes128_cbc.init(sc_sessionkey, Cipher.MODE_DECRYPT, buffer, offset, SIZE_SC_IV); offset+=SIZE_SC_IV; bytesLeft-=SIZE_SC_IV; //decrypt command offset+=2; bytesLeft-=2; if (bytesLeft<sizein) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); short sizeout=sc_aes128_cbc.doFinal(buffer, offset, sizein, buffer, (short) (0)); return sizeout; }
Example 14
Source File: U2FApplet.java From CCU2F with Apache License 2.0 | 4 votes |
private void handleSign(APDU apdu) throws ISOException { byte[] buffer = apdu.getBuffer(); short len = apdu.setIncomingAndReceive(); short dataOffset = apdu.getOffsetCdata(); byte p1 = buffer[ISO7816.OFFSET_P1]; boolean sign = false; boolean counterOverflow = true; short keyHandleLength; boolean extendedLength = (dataOffset != ISO7816.OFFSET_CDATA); short outOffset = SCRATCH_PAD; if (len < 65) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } switch(p1) { case P1_SIGN_OPERATION: sign = true; break; case P1_SIGN_CHECK_ONLY: break; default: ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); } // Check if the counter overflowed if (counterOverflowed) { ISOException.throwIt(ISO7816.SW_FILE_FULL); } // Verify key handle if (localPrivateTransient) { Secp256r1.setCommonCurveParameters(localPrivateKey); } keyHandleLength = (short)(buffer[(short)(dataOffset + 64)] & 0xff); if (!fidoImpl.unwrap(buffer, (short)(dataOffset + 65), keyHandleLength, buffer, (short)(dataOffset + APDU_APPLICATION_PARAMETER_OFFSET), (sign ? localPrivateKey : null))) { ISOException.throwIt(FIDO_SW_INVALID_KEY_HANDLE); } // If not signing, return with the "correct" exception if (!sign) { ISOException.throwIt(FIDO_SW_TEST_OF_PRESENCE_REQUIRED); } // If signing, only proceed if user presence can be validated if ((flags & INSTALL_FLAG_DISABLE_USER_PRESENCE) == 0) { if (scratchPersistent[0] != 0) { ISOException.throwIt(FIDO_SW_TEST_OF_PRESENCE_REQUIRED); } } scratchPersistent[0] = (byte)1; // Increase the counter boolean carry = false; JCSystem.beginTransaction(); for (byte i=0; i<4; i++) { short addValue = (i == 0 ? (short)1 : (short)0); short val = (short)((short)(counter[(short)(4 - 1 - i)] & 0xff) + addValue); if (carry) { val++; } carry = (val > 255); counter[(short)(4 - 1 - i)] = (byte)val; } JCSystem.commitTransaction(); if (carry) { // Game over counterOverflowed = true; ISOException.throwIt(ISO7816.SW_FILE_FULL); } // Prepare reply scratch[outOffset++] = FLAG_USER_PRESENCE_VERIFIED; outOffset = Util.arrayCopyNonAtomic(counter, (short)0, scratch, outOffset, (short)4); localSignature.init(localPrivateKey, Signature.MODE_SIGN); localSignature.update(buffer, (short)(dataOffset + APDU_APPLICATION_PARAMETER_OFFSET), (short)32); localSignature.update(scratch, SCRATCH_PAD, (short)5); outOffset += localSignature.sign(buffer, (short)(dataOffset + APDU_CHALLENGE_OFFSET), (short)32, scratch, outOffset); if (extendedLength) { // If using extended length, the message can be completed and sent immediately scratch[SCRATCH_TRANSPORT_STATE] = TRANSPORT_EXTENDED; Util.arrayCopyNonAtomic(scratch, SCRATCH_PAD, buffer, (short)0, outOffset); apdu.setOutgoingAndSend((short)0, (short)(outOffset - SCRATCH_PAD)); } else { // Otherwise send the first chunk scratch[SCRATCH_TRANSPORT_STATE] = TRANSPORT_NOT_EXTENDED; Util.setShort(scratch, SCRATCH_CURRENT_OFFSET, (short)0); Util.setShort(scratch, SCRATCH_SIGNATURE_LENGTH, (short)0); Util.setShort(scratch, SCRATCH_NONCERT_LENGTH, (short)(outOffset - SCRATCH_PAD)); Util.setShort(scratch, SCRATCH_FULL_LENGTH, (short)(outOffset - SCRATCH_PAD)); scratch[SCRATCH_INCLUDE_CERT] = (byte)0; handleGetData(apdu); } }
Example 15
Source File: CardEdge.java From SatochipApplet with GNU Affero General Public License v3.0 | 4 votes |
/** * This function encrypts/decrypt a given message with a 16bytes secret key derived from the 2FA key. * It also returns an id derived from the 2FA key. * This is used to privately exchange tx data between the hw wallet and the 2FA device. * * Algorithms: * id_2FA is hmac-sha1(secret_2FA, "id_2FA"), * key_2FA is hmac-sha1(secret_2FA, "key_2FA"), * message encrypted using AES * * ins: 0x76 * p1: 0x00 for encryption, 0x01 for decryption * p2: Init-Update-Finalize * data(init): IF_ENCRYPT: none ELSE: [IV(16b)] * data(update/finalize): [chunk_size(2b) | chunk_data] * * return(init): IF_ENCRYPT:[IV(16b) | id_2FA(20b)] ELSE: none * return(update/finalize): [chunk_size(2b) | chunk_data] * * */ private short CryptTransaction2FA(APDU apdu, byte[] buffer){ // check that PIN[0] has been entered previously if (!pins[0].isValidated()) ISOException.throwIt(SW_UNAUTHORIZED); // check that 2FA is enabled if (!needs_2FA) ISOException.throwIt(SW_2FA_UNINITIALIZED_KEY); byte ciph_dir = buffer[ISO7816.OFFSET_P1]; byte ciph_op = buffer[ISO7816.OFFSET_P2]; short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]); short dataOffset = ISO7816.OFFSET_CDATA; short IVlength=(short)16; switch(ciph_op){ case OP_INIT: if (ciph_dir!=Cipher.MODE_ENCRYPT && ciph_dir!=Cipher.MODE_DECRYPT ) ISOException.throwIt(SW_INVALID_PARAMETER); if (ciph_dir==Cipher.MODE_ENCRYPT){ randomData.generateData(buffer,(short)0, IVlength); aes128_cbc.init(key_2FA, Cipher.MODE_ENCRYPT, buffer, (short)0, IVlength); Util.arrayCopyNonAtomic(data2FA, OFFSET_2FA_ID, buffer, (short)IVlength, (short)20); return (short)(IVlength + 20); } if (ciph_dir==Cipher.MODE_DECRYPT){ aes128_cbc.init(key_2FA, Cipher.MODE_DECRYPT, buffer, dataOffset, IVlength); return (short)0; } break; case OP_PROCESS: case OP_FINALIZE: if (bytesLeft < 2) ISOException.throwIt(SW_INVALID_PARAMETER); short size = Util.getShort(buffer, dataOffset); if (bytesLeft < (short) (2 + size)) ISOException.throwIt(SW_INVALID_PARAMETER); short sizeout=0; if (ciph_op == OP_PROCESS){ sizeout=aes128_cbc.update(buffer, (short) (dataOffset + 2), size, buffer, (short) 2); } else {// ciph_op == OP_FINALIZE sizeout=aes128_cbc.doFinal(buffer, (short) (dataOffset + 2), size, buffer, (short) 2); } // Also copies the Short size information Util.setShort(buffer,(short)0, sizeout); return (short) (sizeout + 2); default: ISOException.throwIt(SW_INCORRECT_P2); } return (short)0; }
Example 16
Source File: Gpg.java From OpenPGP-Card with GNU General Public License v3.0 | 4 votes |
/** * The PUT DATA APDU implementation. */ private void putData(APDU apdu) { byte[] buffer = apdu.getBuffer(); short length = (short) (buffer[ISO7816.OFFSET_LC] & 0x00FF); short tag = Util.getShort(buffer, ISO7816.OFFSET_P1); switch (tag) { // Private use objects. case 0x101: storeVariableLength(apdu, privateDO1, PIN_INDEX_PW1); break; case 0x102: storeVariableLength(apdu, privateDO2, PIN_INDEX_PW3); break; case 0x103: storeVariableLength(apdu, privateDO3, PIN_INDEX_PW1); break; case 0x104: storeVariableLength(apdu, privateDO4, PIN_INDEX_PW3); break; case 0x5B: storeVariableLength(apdu, name, PIN_INDEX_PW3); break; case 0x5E: storeVariableLength(apdu, loginData, PIN_INDEX_PW3); break; case 0x5F2D: storeVariableLength(apdu, language, PIN_INDEX_PW3); break; case 0x5F35: storeFixedLength(apdu, sex, (short) 0, (short) 1); break; case 0x5F50: storeVariableLength(apdu, url, PIN_INDEX_PW3); break; case 0xC4: if (!pins[PIN_INDEX_PW3].isValidated()) { ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED); } if (length < (short) 1 || length > (short) 8 || length != apdu.setIncomingAndReceive()) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } pinValidForMultipleSignatures = buffer[ISO7816.OFFSET_CDATA]; break; case 0xC7: case 0xC8: case 0xC9: storeFixedLength(apdu, fingerprints, (short) (20 * (tag - 0xC7)), (short) 20); break; case 0xCA: case 0xCB: case 0xCC: storeFixedLength(apdu, caFingerprints, (short) (20 * (tag - 0xCA)), (short) 20); break; case 0xCE: case 0xCF: case 0xD0: storeFixedLength(apdu, generationDates, (short) (4 * (tag - 0xCE)), (short) 4); break; case 0xD3: storeVariableLength(apdu, buffer, PIN_INDEX_PW3); // Reset code must be zero or 8 - MAX_PIN_LENGTH. if (length > MAX_PIN_LENGTH || (length != (byte) 0 && length < (byte) 8)) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } updatePIN(PIN_INDEX_RC, buffer, (short) 1, buffer[0]); break; default: ISOException.throwIt(ISO7816.SW_RECORD_NOT_FOUND); } }
Example 17
Source File: CardEdge.java From SatochipApplet with GNU Affero General Public License v3.0 | 4 votes |
/** * This function imports a Bip32 seed to the applet and derives the master key and chain code. * It also derives a second ECC that uniquely authenticates the HDwallet: the authentikey. * Lastly, it derives a 32-bit AES key that is used to encrypt/decrypt Bip32 object stored in secure memory * If the seed already exists, it is reset if the logged identities allow it. * * The function returns the x-coordinate of the authentikey, self-signed. * The authentikey full public key can be recovered from the signature. * * ins: 0x6C * p1: seed_size(1b) * p2: 0x00 * data: [seed_data (seed_size)] * return: [coordx_size(2b) | coordx | sig_size(2b) | sig] */ private short importBIP32Seed(APDU apdu, byte[] buffer){ // check that PIN[0] has been entered previously if (!pins[0].isValidated()) ISOException.throwIt(SW_UNAUTHORIZED); if (buffer[ISO7816.OFFSET_P2] != (byte) 0x00) ISOException.throwIt(SW_INCORRECT_P2); // if already seeded, must call resetBIP32Seed first! if (bip32_seeded) ISOException.throwIt(SW_BIP32_INITIALIZED_SEED); short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]); // get seed bytesize (max 64 bytes) byte bip32_seedsize = buffer[ISO7816.OFFSET_P1]; if (bip32_seedsize <0 || bip32_seedsize>64) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); short offset= (short)ISO7816.OFFSET_CDATA; // derive master key! HmacSha512.computeHmacSha512(BITCOIN_SEED, (short)0, (short)BITCOIN_SEED.length, buffer, offset, (short)bip32_seedsize, recvBuffer, (short)0); bip32_masterkey.setKey(recvBuffer, (short)0); // data must be exactly 32 bytes long bip32_masterchaincode.setKey(recvBuffer, (short)32); // data must be exactly 32 bytes long // derive 2 more keys from seed: // - AES encryption key for secure storage of extended keys in object // - ECC key for authentication of sensitive data returned by the applet (hash, pubkeys) HmacSha512.computeHmacSha512(BITCOIN_SEED2, (short)0, (short)BITCOIN_SEED2.length, buffer, offset, (short)bip32_seedsize, recvBuffer, (short)64); bip32_authentikey.setS(recvBuffer, (short)64, BIP32_KEY_SIZE); bip32_encryptkey.setKey(recvBuffer, (short)96); // AES-128: 16-bytes key!! // bip32 is now seeded bip32_seeded= true; // clear recvBuffer Util.arrayFillNonAtomic(recvBuffer, (short)0, (short)128, (byte)0); // compute the partial authentikey public key... keyAgreement.init(bip32_authentikey); short coordx_size= (short)32; keyAgreement.generateSecret(Secp256k1.SECP256K1, Secp256k1.OFFSET_SECP256K1_G, (short) 65, authentikey_pubkey, (short)0); //pubkey in uncompressed form Util.setShort(buffer, (short)0, coordx_size); Util.arrayCopyNonAtomic(authentikey_pubkey, (short)1, buffer, (short)2, coordx_size); // self signed public key sigECDSA.init(bip32_authentikey, Signature.MODE_SIGN); short sign_size= sigECDSA.sign(buffer, (short)0, (short)(coordx_size+2), buffer, (short)(coordx_size+4)); Util.setShort(buffer, (short)(2+coordx_size), sign_size); // return x-coordinate of public key+signature // the client can recover full public-key from the signature or // by guessing the compression value () and verifying the signature... // buffer= [coordx_size(2) | coordx | sigsize(2) | sig] return (short)(2+coordx_size+2+sign_size); }
Example 18
Source File: CardEdge.java From SatochipApplet with GNU Affero General Public License v3.0 | 4 votes |
/** * This function changes a PIN code. The DATA portion contains both the old and * the new PIN codes. * * ins: 0x44 * p1: PIN number (0x00-0x07) * p2: 0x00 * data: [PIN_size(1b) | old_PIN | PIN_size(1b) | new_PIN ] * return: none (throws an exception in case of wrong PIN) */ private short ChangePIN(APDU apdu, byte[] buffer) { /* * Here I suppose the PIN code is small enough that 2 of them enter in * the buffer TODO: Verify the assumption and eventually adjust code to * support reading PINs in multiple read()s */ byte pin_nb = buffer[ISO7816.OFFSET_P1]; if ((pin_nb < 0) || (pin_nb >= MAX_NUM_PINS)) ISOException.throwIt(SW_INCORRECT_P1); OwnerPIN pin = pins[pin_nb]; if (pin == null) ISOException.throwIt(SW_INCORRECT_P1); if (buffer[ISO7816.OFFSET_P2] != (byte) 0x00) ISOException.throwIt(SW_INCORRECT_P2); short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]); // At least 1 character for each PIN code if (bytesLeft < 4) ISOException.throwIt(SW_INVALID_PARAMETER); byte pin_size = buffer[ISO7816.OFFSET_CDATA]; if (bytesLeft < (short) (1 + pin_size + 1)) ISOException.throwIt(SW_INVALID_PARAMETER); if (!CheckPINPolicy(buffer, (short) (ISO7816.OFFSET_CDATA + 1), pin_size)) ISOException.throwIt(SW_INVALID_PARAMETER); byte new_pin_size = buffer[(short) (ISO7816.OFFSET_CDATA + 1 + pin_size)]; if (bytesLeft < (short) (1 + pin_size + 1 + new_pin_size)) ISOException.throwIt(SW_INVALID_PARAMETER); if (!CheckPINPolicy(buffer, (short) (ISO7816.OFFSET_CDATA + 1 + pin_size + 1), new_pin_size)) ISOException.throwIt(SW_INVALID_PARAMETER); byte triesRemaining = pin.getTriesRemaining(); if (triesRemaining == (byte) 0x00) ISOException.throwIt(SW_IDENTITY_BLOCKED); if (!pin.check(buffer, (short) (ISO7816.OFFSET_CDATA + 1), pin_size)) { LogoutIdentity(pin_nb); ISOException.throwIt((short)(SW_PIN_FAILED + triesRemaining - 1)); } pin.update(buffer, (short) (ISO7816.OFFSET_CDATA + 1 + pin_size + 1), new_pin_size); // JC specifies this resets the validated flag. So we do. logged_ids &= (short) ((short) 0xFFFF ^ (0x01 << pin_nb)); return (short)0; }
Example 19
Source File: ECTesterApplet.java From ECTester with MIT License | 4 votes |
short getOffsetCdata(APDU apdu) { return ISO7816.OFFSET_CDATA; }
Example 20
Source File: LedgerWalletApplet.java From ledger-javacard with GNU Affero General Public License v3.0 | 4 votes |
private static void handleSetUserKeycard(APDU apdu, boolean airgap) throws ISOException { byte[] buffer = apdu.getBuffer(); short offset = ISO7816.OFFSET_CDATA; apdu.setIncomingAndReceive(); if ((setup == TC.FALSE) || (setup != TC.TRUE)) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } if (Keycard.issuerKeycardSize == (byte)0) { ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); } if (buffer[ISO7816.OFFSET_P1] == P1_SET_KEYCARD) { if (buffer[ISO7816.OFFSET_LC] != (byte)(KEYCARD_KEY_LENGTH + 1)) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } Keycard.setPairingData(buffer, ISO7816.OFFSET_CDATA); Keycard.generateRandomIndexes(Keycard.challenge, (short)0, KEYCARD_CHALLENGE_LENGTH); buffer[0] = CONFIRM_PREVIOUS_KEYCARD; Util.arrayCopyNonAtomic(Keycard.challenge, (short)0, buffer, (short)1, KEYCARD_CHALLENGE_LENGTH); apdu.setOutgoingAndSend((short)0, (short)(KEYCARD_CHALLENGE_LENGTH + 1)); } else if (buffer[ISO7816.OFFSET_P1] == P1_CONFIRM_KEYCARD) { if (buffer[ISO7816.OFFSET_LC] != KEYCARD_CHALLENGE_LENGTH) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } if (!Keycard.check(null, (short)0, (byte)0, buffer, ISO7816.OFFSET_CDATA, (byte)4, Keycard.challenge, (short)0, scratch256, (short)150)) { Keycard.clearPairingData(); ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED); } else { Keycard.getPairingData(scratch256, (short)0); if (!airgap) { Keycard.setUser(scratch256[0], scratch256, (short)1); } else { Crypto.initCipherAES(pairingKey, false); Crypto.blobEncryptDecryptAES.doFinal(scratch256, (short)1, (short)16, scratch256, (short)100); Keycard.setUser(scratch256[0], scratch256, (short)100); } } } else { ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); } }