Java Code Examples for javacard.framework.ISO7816#OFFSET_P2

The following examples show how to use javacard.framework.ISO7816#OFFSET_P2 . 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: OCUnitTests.java    From JCMathLib with MIT License 6 votes vote down vote up
void test_BN_EXP(APDU apdu, short dataLen) {
    byte[] apdubuf = apdu.getBuffer();
    short p1 = (short) (apdubuf[ISO7816.OFFSET_P1] & 0x00FF);
    short p2 = (short) (apdubuf[ISO7816.OFFSET_P2] & 0x00FF);

    PM.check(PM.TRAP_BN_EXP_1);    
    Bignat base = m_testBN1;
    base.set_size(p1);
    PM.check(PM.TRAP_BN_EXP_2);
    Bignat exp = m_testBN2;
    exp.set_size((short) (dataLen - p1));
    PM.check(PM.TRAP_BN_EXP_3);
    Bignat res = m_testBN3;
    res.set_size((short) (m_ecc.MAX_BIGNAT_SIZE / 2));
    PM.check(PM.TRAP_BN_EXP_4);
    base.from_byte_array(p1, (short) 0, apdubuf, ISO7816.OFFSET_CDATA);
    exp.from_byte_array((short) (dataLen - p1), (short) 0, apdubuf, (short)(ISO7816.OFFSET_CDATA+p1));
    PM.check(PM.TRAP_BN_EXP_5);
    res.exponentiation(base, exp);
    PM.check(PM.TRAP_BN_EXP_6);
    short len = res.copy_to_buffer(apdubuf, (short) 0);
    apdu.setOutgoingAndSend((short) 0, len);
}
 
Example 2
Source File: CardEdge.java    From SatochipApplet with GNU Affero General Public License v3.0 6 votes vote down vote up
/**
 * This function returns a 2 byte bit mask of the available PINs that are currently in
 * use. Each set bit corresponds to an active PIN.
 * 
 *  ins: 0x48
 *  p1: 0x00
 *  p2: 0x00
 *  data: none
 *  return: [RFU(1b) | PIN_mask(1b)]
 */
private short ListPINs(APDU apdu, byte[] buffer) {
	// check that PIN[0] has been entered previously
	if (!pins[0].isValidated())
		ISOException.throwIt(SW_UNAUTHORIZED);
	
	// Checking P1 & P2
	if (buffer[ISO7816.OFFSET_P1] != (byte) 0x00)
		ISOException.throwIt(SW_INCORRECT_P1);
	if (buffer[ISO7816.OFFSET_P2] != (byte) 0x00)
		ISOException.throwIt(SW_INCORRECT_P2);
	byte expectedBytes = (byte) (buffer[ISO7816.OFFSET_LC]);
	if (expectedBytes != (short) 2)
		ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
	// Build the PIN bit mask
	short mask = (short) 0x00;
	short b;
	for (b = (short) 0; b < MAX_NUM_PINS; b++)
		if (pins[b] != null)
			mask |= (short) (((short) 0x01) << b);
	// Fill the buffer
	Util.setShort(buffer, (short) 0, mask);
	// Send response
	return (short)2;
}
 
Example 3
Source File: OCUnitTests.java    From JCMathLib with MIT License 6 votes vote down vote up
void test_BN_POW2_MOD(APDU apdu, short dataLen) {
    byte[] apdubuf = apdu.getBuffer();
    short p1 = (short) (apdubuf[ISO7816.OFFSET_P1] & 0x00FF);
    short p2 = (short) (apdubuf[ISO7816.OFFSET_P2] & 0x00FF);

    PM.check(PM.TRAP_BN_POW2_MOD_1);
    Bignat num1 = m_testBN1;
    num1.set_size(p1);
    Bignat mod = m_testBN3;
    mod.set_size((short) (dataLen - p1));
    num1.from_byte_array(p1, (short) 0, apdubuf, ISO7816.OFFSET_CDATA);
    mod.from_byte_array((short) (dataLen - p1), (short) 0, apdubuf, (short) (ISO7816.OFFSET_CDATA + p1));
    PM.check(PM.TRAP_BN_POW2_MOD_2);
    //num1.pow2Mod_RSATrick(mod);
    num1.mod_exp2(mod);
    PM.check(PM.TRAP_BN_POW2_MOD_3);
    short len = num1.copy_to_buffer(apdubuf, (short) 0);
    apdu.setOutgoingAndSend((short) 0, len);
}
 
Example 4
Source File: OCUnitTests.java    From JCMathLib with MIT License 6 votes vote down vote up
void test_EC_SETCURVE_G(APDU apdu, short dataLen) {
     byte[] apdubuf = apdu.getBuffer();
     
     Util.arrayCopyNonAtomic(apdubuf, ISO7816.OFFSET_CDATA, m_customG, (short) 0, dataLen);
     PM.check(PM.TRAP_EC_SETCURVE_1);

     if (apdubuf[ISO7816.OFFSET_P2] == 1) { // If required, complete new custom curve and point is allocated
         m_testCurveCustom = new ECCurve(false, SecP256r1.p, SecP256r1.a, SecP256r1.b, m_customG, SecP256r1.r);
         m_testPointCustom = new ECPoint(m_testCurveCustom, m_ecc.ech);
         PM.check(PM.TRAP_EC_SETCURVE_2);
         // Release unused previous objects
         if (!bIsSimulator) {
             JCSystem.requestObjectDeletion();
         }
     }
     else {
         // Otherwise, only G is set and relevant objects are updated
         m_testCurveCustom.setG(apdubuf, (short) ISO7816.OFFSET_CDATA, m_testCurveCustom.POINT_SIZE);
         m_testPointCustom.updatePointObjects(); // After changing curve parameters, internal objects needs to be actualized
     }
}
 
Example 5
Source File: GidsApplet.java    From GidsApplet with GNU General Public License v3.0 5 votes vote down vote up
/**
 * \brief Process the PERFORM SECURITY OPERATION apdu (INS=2A).
 *
 * This operation is used for cryptographic operations
 * (Computation of digital signatures, decrypting.).
 *
 * \param apdu The PERFORM SECURITY OPERATION apdu.
 *
 * \throw ISOException SW_SECURITY_STATUS_NOT_SATISFIED, SW_INCORRECT_P1P2 and
 * 			the ones from computeDigitalSignature() and decipher().
 */
private void processPerformSecurityOperation(APDU apdu) throws ISOException {
    byte[] buf = apdu.getBuffer();
    byte p1 = buf[ISO7816.OFFSET_P1];
    byte p2 = buf[ISO7816.OFFSET_P2];

    if(p1 == (byte) 0x9E && p2 == (byte) 0x9A) {
        computeDigitalSignature(apdu);
    } else if(p1 == (byte) 0x80 && p2 == (byte) 0x86) {
        decipher(apdu);
    } else {
        ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
    }

}
 
Example 6
Source File: Gpg.java    From OpenPGP-Card with GNU General Public License v3.0 5 votes vote down vote up
/**
 * CHANGE REFERENCE DATA APDU implementation.
 */
private void changeReferenceData(APDU apdu) {
  byte buffer[] = apdu.getBuffer();
  if (buffer[ISO7816.OFFSET_P1] != (byte) 0) {
    ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
  }
  byte pinOffset = PIN_INDEX_PW1;
  byte minLength = MIN_PIN1_LENGTH;
  byte type = buffer[ISO7816.OFFSET_P2];
  if (type == (byte) 0x83) {
    pinOffset = PIN_INDEX_PW3;
    minLength = MIN_PIN3_LENGTH;
  } else if (type != (byte) 0x81) {
    ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
  }
  byte currentLength = pinLength[pinOffset];
  short length = (short) (buffer[ISO7816.OFFSET_LC] & 0x00FF);
  if (apdu.setIncomingAndReceive() != length ||
      length > currentLength + MAX_PIN_LENGTH ||
      length < currentLength + minLength) {
    ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
  }
  if (pins[pinOffset].getTriesRemaining() == 0) {
    ISOException.throwIt(SW_PIN_BLOCKED);
  }
  if (!pins[pinOffset].check(buffer, ISO7816.OFFSET_CDATA, currentLength)) {
    pinSubmitted[0] = false;
    ISOException.throwIt((short) (SW_PIN_FAILED_00 + pins[pinOffset].getTriesRemaining()));
  }
  updatePIN(pinOffset, buffer, (short) (ISO7816.OFFSET_CDATA + currentLength),
            (byte) (length - currentLength));
}
 
Example 7
Source File: NdefApplet.java    From openjavacard-ndef with GNU General Public License v3.0 5 votes vote down vote up
/**
 * Process a SELECT command
 *
 * This handles only the one case mandated by the NDEF
 * specification: SELECT FIRST-OR-ONLY BY-FILE-ID.
 *
 * The file ID is specified in the APDU contents. It
 * must be exactly two bytes long and also valid.
 *
 * @param apdu to process
 * @throws ISOException on error
 */
private void processSelect(APDU apdu) throws ISOException {
    byte[] buffer = apdu.getBuffer();
    byte p1 = buffer[ISO7816.OFFSET_P1];
    byte p2 = buffer[ISO7816.OFFSET_P2];

    // we only support what the NDEF spec prescribes
    if(p1 != SELECT_P1_BY_FILEID || p2 != SELECT_P2_FIRST_OR_ONLY) {
        ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
    }

    // receive data
    short lc = apdu.setIncomingAndReceive();

    // check length, must be for a file ID
    if(lc != 2) {
        ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
    }

    // retrieve the file ID
    short fileId = Util.getShort(buffer, ISO7816.OFFSET_CDATA);

    // perform selection if the ID is valid
    if(fileId == FILEID_NDEF_CAPABILITIES || fileId == FILEID_NDEF_DATA) {
        vars[VAR_SELECTED_FILE] = fileId;
    } else {
        ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND);
    }
}
 
Example 8
Source File: NdefApplet.java    From openjavacard-ndef with GNU General Public License v3.0 5 votes vote down vote up
/**
 * Process a SELECT command
 *
 * This handles only the one case mandated by the NDEF
 * specification: SELECT FIRST-OR-ONLY BY-FILE-ID.
 *
 * The file ID is specified in the APDU contents. It
 * must be exactly two bytes long and also valid.
 *
 * @param apdu to process
 * @throws ISOException on error
 */
private void processSelect(APDU apdu) throws ISOException {
    byte[] buffer = apdu.getBuffer();
    byte p1 = buffer[ISO7816.OFFSET_P1];
    byte p2 = buffer[ISO7816.OFFSET_P2];

    // we only support what the NDEF spec prescribes
    if(p1 != SELECT_P1_BY_FILEID || p2 != SELECT_P2_FIRST_OR_ONLY) {
        ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
    }

    // receive data
    short lc = apdu.setIncomingAndReceive();

    // check length, must be for a file ID
    if(lc != 2) {
        ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
    }

    // retrieve the file ID
    short fileId = Util.getShort(buffer, ISO7816.OFFSET_CDATA);

    // perform selection if the ID is valid
    if(fileId == FILEID_NDEF_CAPABILITIES || fileId == FILEID_NDEF_DATA) {
        vars[VAR_SELECTED_FILE] = fileId;
    } else {
        ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND);
    }
}
 
Example 9
Source File: NdefApplet.java    From openjavacard-ndef with GNU General Public License v3.0 5 votes vote down vote up
/**
 * Process a SELECT command
 *
 * This handles only the one case mandated by the NDEF
 * specification: SELECT FIRST-OR-ONLY BY-FILE-ID.
 *
 * The file ID is specified in the APDU contents. It
 * must be exactly two bytes long and also valid.
 *
 * @param apdu to process
 * @throws ISOException on error
 */
private void processSelect(APDU apdu) throws ISOException {
    byte[] buffer = apdu.getBuffer();
    byte p1 = buffer[ISO7816.OFFSET_P1];
    byte p2 = buffer[ISO7816.OFFSET_P2];

    // we only support what the NDEF spec prescribes
    if(p1 != SELECT_P1_BY_FILEID || p2 != SELECT_P2_FIRST_OR_ONLY) {
        ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
    }

    // receive data
    short lc = apdu.setIncomingAndReceive();

    // check length, must be for a file ID
    if(lc != 2) {
        ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
    }

    // retrieve the file ID
    short fileId = Util.getShort(buffer, ISO7816.OFFSET_CDATA);

    // perform selection if the ID is valid
    if(fileId == FILEID_NDEF_CAPABILITIES || fileId == FILEID_NDEF_DATA) {
        vars[VAR_SELECTED_FILE] = fileId;
    } else {
        ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND);
    }
}
 
Example 10
Source File: CardEdge.java    From SatochipApplet with GNU Affero General Public License v3.0 5 votes vote down vote up
/** 
 * This function verifies a PIN number sent by the DATA portion. The length of
 * this PIN is specified by the value contained in P3.
 * Multiple consecutive unsuccessful PIN verifications will block the PIN. If a PIN
 * blocks, then an UnblockPIN command can be issued.
 * 
 * ins: 0x42
 * p1: PIN number (0x00-0x07)
 * p2: 0x00
 * data: [PIN] 
 * return: none (throws an exception in case of wrong PIN)
 */
private short VerifyPIN(APDU apdu, byte[] buffer) {
	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] != 0x00)
		ISOException.throwIt(SW_INCORRECT_P2);
	short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]);
	/*
	 * Here I suppose the PIN code is small enough to enter in the buffer
	 * TODO: Verify the assumption and eventually adjust code to support
	 * reading PIN in multiple read()s
	 */
	if (!CheckPINPolicy(buffer, ISO7816.OFFSET_CDATA, (byte) bytesLeft))
		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, (byte) bytesLeft)) {
		LogoutIdentity(pin_nb);
		ISOException.throwIt((short)(SW_PIN_FAILED + triesRemaining - 1));
	}
	
	// Actually register that PIN has been successfully verified.
	logged_ids |= (short) (0x0001 << pin_nb);
	
	return (short)0;
}
 
Example 11
Source File: Gpg.java    From OpenPGP-Card with GNU General Public License v3.0 5 votes vote down vote up
/**
 * VERIFY APDU implementation.
 */
private void verify(APDU apdu) {
  byte buffer[] = apdu.getBuffer();
  if (buffer[ISO7816.OFFSET_P1] != (byte) 0) {
    ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
  }
  // type = 0x81 or 0x82 -> PIN1, min length = 6
  // type = 0x83 -> PIN2, min length = 8
  byte pinOffset = PIN_INDEX_PW1;
  byte type = buffer[ISO7816.OFFSET_P2];
  byte minLength = MIN_PIN1_LENGTH;
  if (type == (byte) 0x83) {
    pinOffset = PIN_INDEX_PW3;
    minLength = MIN_PIN3_LENGTH;
  } else if (type != (byte) 0x81 && type != (byte) 0x82) {
    ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
  }
  short length = (short) (buffer[ISO7816.OFFSET_LC] & 0x00FF);
  if (apdu.setIncomingAndReceive() != length ||
      length > MAX_PIN_LENGTH ||
      length < minLength) {
    ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
  }
  if (pins[pinOffset].getTriesRemaining() == 0) {
    ISOException.throwIt(SW_PIN_BLOCKED);
  }
  boolean result = pins[pinOffset].check(buffer, ISO7816.OFFSET_CDATA, (byte) length);
  if (type != (byte) 0x83) {
    pinSubmitted[(byte) (type - 0x81)] = result;
  }
  if (result) {
    ISOException.throwIt(ISO7816.SW_NO_ERROR);
  }
  ISOException.throwIt((short) (SW_PIN_FAILED_00 + pins[pinOffset].getTriesRemaining()));
}
 
Example 12
Source File: CardEdge.java    From SatochipApplet with GNU Affero General Public License v3.0 5 votes vote down vote up
/** 
 * 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 13
Source File: LedgerWalletApplet.java    From ledger-javacard with GNU Affero General Public License v3.0 4 votes vote down vote up
private static void handleHashTransaction(APDU apdu) throws ISOException {
    byte[] buffer = apdu.getBuffer();
    byte p1 = buffer[ISO7816.OFFSET_P1];
    byte p2 = buffer[ISO7816.OFFSET_P2];
    short dataOffset = (short)0;
    apdu.setIncomingAndReceive();
    if (p1 == P1_HASH_TRANSACTION_FIRST) {
        TC.clear();
        TC.ctx[TC.TX_B_TRANSACTION_STATE] = Transaction.STATE_NONE;
        TC.ctx[TC.TX_B_HASH_OPTION] = Transaction.HASH_BOTH;
        TC.ctx[TC.TX_Z_CHANGE_ACCEPTED] = (byte)0x01;
    }
    else
    if (p1 != P1_HASH_TRANSACTION_NEXT) {
        ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
    }
    if (p2 == P2_HASH_TRANSACTION_NEW_INPUT) {
        if (p1 == P1_HASH_TRANSACTION_FIRST) {
            checkAccess(true);
            TC.ctxP[TC.P_TX_Z_WIRED] = (isContactless() ? TC.FALSE : TC.TRUE);
            TC.ctxP[TC.P_TX_Z_FIRST_SIGNED] = TC.TRUE;
            TC.ctxP[TC.P_TX_Z_RELAXED] = TC.FALSE;
            TC.ctxP[TC.P_TX_Z_CONSUME_P2SH] = TC.FALSE;
            TC.ctxP[TC.P_TX_Z_USE_KEYCARD] = TC.FALSE;
            Crypto.random.generateData(TC.ctxP, TC.P_TX_A_NONCE, TC.SIZEOF_NONCE);
        }
    }
    else
    if (p2 != P2_HASH_TRANSACTION_CONTINUE_INPUT) {
        ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
    }
    checkInterfaceConsistency();
    short remainingData = (short)((short)(buffer[ISO7816.OFFSET_LC] & 0xff) - dataOffset);
    byte result = Transaction.parseTransaction(Transaction.PARSE_SIGNATURE, buffer, (short)(ISO7816.OFFSET_CDATA + dataOffset), remainingData);
    if (result == Transaction.RESULT_ERROR) {
        ISOException.throwIt(ISO7816.SW_WRONG_DATA);
    }
    else
    if (result == Transaction.RESULT_MORE) {
        return;
    }
    else
    if (result == Transaction.RESULT_FINISHED) {
        return;
    }
}
 
Example 14
Source File: CardEdge.java    From SatochipApplet with GNU Affero General Public License v3.0 4 votes vote down vote up
/**
 * 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 15
Source File: TransitApplet.java    From JCMathLib with MIT License 4 votes vote down vote up
/**
 * Processes an incoming request. The request message signature is verified,
 * then it is dispatched to the relevant handling method. The response
 * message is then signed and sent back.
 * 
 * @param apdu
 *            The APDU
 */
private void processRequest(APDU apdu) {

    // C-APDU: [CLA, INS, P1, P2, LC, [Request Message], [8-bytes MAC]]
    // Request Message: [T, L, [V...]]

    byte[] buffer = apdu.getBuffer();

    if ((buffer[ISO7816.OFFSET_P1] != 0)
            || (buffer[ISO7816.OFFSET_P2] != 0)) {
        ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
    }

    byte numBytes = buffer[ISO7816.OFFSET_LC];

    byte count = (byte) apdu.setIncomingAndReceive();

    if (numBytes != count) {
        ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
    }

    // Check request message signature
    if (!checkMAC(buffer)) {
        ISOException.throwIt(SW_WRONG_SIGNATURE);
    }

    if ((numBytes - MAC_LENGTH) != (buffer[TLV_LENGTH_OFFSET] + 2)) {
        ISOException.throwIt(ISO7816.SW_WRONG_DATA);
    }

    // R-APDU: [[Response Message], [2-bytes Status Word], [8-bytes MAC]]

    short offset = 0;

    // Dispatch request message for processing
    switch (buffer[TLV_TAG_OFFSET]) {
    case PROCESS_ENTRY:
        offset = processEntry(buffer, TLV_VALUE_OFFSET,
                buffer[TLV_LENGTH_OFFSET]);
        break;
    case PROCESS_EXIT:
        offset = processExit(buffer, TLV_VALUE_OFFSET,
                buffer[TLV_LENGTH_OFFSET]);
        break;
    case CREDIT:
        offset = credit(buffer, TLV_VALUE_OFFSET, buffer[TLV_LENGTH_OFFSET]);
        break;
    case GET_BALANCE:
        offset = getBalance(buffer, TLV_VALUE_OFFSET,
                buffer[TLV_LENGTH_OFFSET]);
        break;
    default:
        ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
    }

    // Append status word to response message
    offset = Util.setShort(buffer, offset, SW_SUCCESS);

    // Sign response message and append MAC to response message
    offset = generateMAC(buffer, offset);

    // Send R-APDU
    apdu.setOutgoingAndSend((short) 0, offset);
}
 
Example 16
Source File: CardEdge.java    From SatochipApplet with GNU Affero General Public License v3.0 4 votes vote down vote up
/**
   * 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 17
Source File: TransitApplet.java    From JCMathLib with MIT License 4 votes vote down vote up
/**
 * Initializes a CAD/card interaction session. This is the first step of
 * mutual authentication. A new card challenge is generated and used along
 * with the passed-in host challenge to generate the derivation data from
 * which a new session key is derived. The card challenge is appended to the
 * response message. The response message is signed using the newly
 * generated session key then sent back. Note that mutual authentication is
 * subsequently completed upon succesful verification of the signature of
 * the first request received.
 * 
 * @param apdu
 *            The APDU
 */
private void initializeSession(APDU apdu) {

    // C-APDU: [CLA, INS, P1, P2, LC, [4-bytes Host Challenge]]

    byte[] buffer = apdu.getBuffer();

    if ((buffer[ISO7816.OFFSET_P1] != 0)
            || (buffer[ISO7816.OFFSET_P2] != 0)) {
        ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
    }

    byte numBytes = buffer[ISO7816.OFFSET_LC];

    byte count = (byte) apdu.setIncomingAndReceive();

    if (numBytes != CHALLENGE_LENGTH || count != CHALLENGE_LENGTH) {
        ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
    }

    // Generate card challenge
    generateCardChallenge();

    // Generate key derivation data from host challenge and card challenge
    generateKeyDerivationData(buffer);

    // Generate session key from derivation data
    generateSessionKey();

    // R-APDU: [[4-bytes Card Challenge], [2-bytes Status Word], [8-bytes
    // MAC]]

    short offset = 0;

    // Append card challenge to response message
    offset = Util.arrayCopyNonAtomic(cardChallenge, (short) 0, buffer,
            offset, CHALLENGE_LENGTH);

    // Append status word to response message
    offset = Util.setShort(buffer, offset, SW_SUCCESS);

    // Sign response message and append MAC to response message
    offset = generateMAC(buffer, offset);

    // Send R-APDU
    apdu.setOutgoingAndSend((short) 0, offset);
}
 
Example 18
Source File: CardAgent.java    From CardExamples with The Unlicense 4 votes vote down vote up
/**
 * Handle Read Record command.
 * 
 * @param apdu
 *            the incoming <code>APDU</code> object
 */
private void readRecord(APDU apdu) throws ISOException {
    byte[] apduBuffer = apdu.getBuffer();

    // DEBUG
    Log.v(LOG_TAG, "C-APDU: " + DataUtil.byteArrayToHexString(apduBuffer, 0, 5));

    final byte recordNumber = apduBuffer[ISO7816.OFFSET_P1];

    // Check P1/P2.
    if ((recordNumber == (byte) 0x00) || 
        ((apduBuffer[ISO7816.OFFSET_P2] & (byte) 0x07) != (byte) 0x04)) {
        ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
    }

    // Check if Lc is not present.
    // Check if Le=0x00.
    if ((apdu.setIncomingAndReceive() != (short) 0) || 
        (apdu.setOutgoing() != (short) 256)) {
        ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
    }

    // Check if AFL saved in Get Processing Options or
    //       if Read Records counter is greater than number of records indicated in AFL.
    if ((this.afl == null) || 
        (this.readRecordCounter > this.aflRecords)) {
        ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
    }

    // Check if SFI and record supported in AFL.
    final byte sfi = (byte) ((apduBuffer[ISO7816.OFFSET_P2] & (byte) 0xF8));
    boolean aflSupported = false;
    this.afl.reset();
    while (this.afl.hasRemaining()) {
        byte aflSfi = this.afl.get();
        byte aflFirstRecord = this.afl.get();
        byte aflLastRecord = this.afl.get();
        if ((aflSfi == sfi) && 
            (aflFirstRecord <= recordNumber) && 
            (aflLastRecord >= recordNumber)) {
            aflSupported = true;
            break;
        }

        // Skip the next byte.
        this.afl.get();
    }
    if (!aflSupported) {
        Log.e(LOG_TAG, "Transaction Failure: SFI and record not supported in AFL.");
        ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND);
    }

    // Retrieve record.
    short sfiRecord = (short) ((sfi << 5) | recordNumber);
    byte[] recordData = this.accountParamsStatic.getSfiRecord(sfiRecord);
    if (recordData == null) {
        if (sfiRecord == (short) 0x0204) {
            recordData = this.dynamicSfi2Record4;
        }
        else {
            // Req 7.23
            Log.e(LOG_TAG, "Transaction Failure: SFI and record not found.");
            ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND);
        }
    }

    // Increment Read Record counter.
    this.readRecordCounter++;

    // Copy record data to APDU response buffer.
    short rdataLength = (short) recordData.length;
    System.arraycopy(recordData, 0, apduBuffer, 0, rdataLength);

    // Determine if this is the last Read Record command.
    if (this.readRecordCounter == this.aflRecords) {
        this.apduState = APDU_SENDING_LAST;
    }
    else {
        this.apduState = APDU_SENDING;
    }

    // DEBUG
    Log.v(LOG_TAG, "R-APDU: " + DataUtil.byteArrayToHexString(apduBuffer, 0, rdataLength) + "9000");

    apdu.setOutgoingLength(rdataLength);
    apdu.sendBytes((short) 0, rdataLength);

    // Determine if this is the last Read Record command.
    if (this.readRecordCounter == this.aflRecords) {
        // Success triggers a successful transaction.
        apdu.setTransactionSuccess();
    }
}
 
Example 19
Source File: IsoApplet.java    From IsoApplet with GNU General Public License v3.0 4 votes vote down vote up
/**
 * \brief Process the RESET RETRY COUNTER apdu (INS = 2C).
 *
 * This is used to unblock the PIN with the PUK and set a new PIN value.
 *
 * \param apdu The RESET RETRY COUNTER apdu.
 *
 * \throw ISOException SW_COMMAND_NOT_ALLOWED, ISO7816.SW_WRONG_LENGTH, SW_INCORRECT_P1P2,
 *			SW_PIN_TRIES_REMAINING.
 */
public void	processResetRetryCounter(APDU apdu) throws ISOException {
    byte[] buf = apdu.getBuffer();
    byte p1 = buf[ISO7816.OFFSET_P1];
    byte p2 = buf[ISO7816.OFFSET_P2];
    short lc;
    short offset_cdata;

    if(state != STATE_OPERATIONAL_ACTIVATED) {
        ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED);
    }

    // Bytes received must be Lc.
    lc = apdu.setIncomingAndReceive();
    if(lc != apdu.getIncomingLength()) {
        ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
    }
    offset_cdata = apdu.getOffsetCdata();

    // Length of data field.
    if(lc < (short)(PUK_LENGTH + PIN_MIN_LENGTH)
            || lc > (short)(PUK_LENGTH + PIN_MAX_LENGTH)) {
        ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
    }

    // We expect the PUK followed by a new PIN.
    if(p1 != (byte) 0x00 || p2 != (byte) 0x01) {
        ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
    }

    // Check the PUK.
    if(puk == null) {
        ISOException.throwIt(SW_PIN_TRIES_REMAINING);
    } else if (!puk.check(buf, offset_cdata, PUK_LENGTH)) {
        ISOException.throwIt((short)(SW_PIN_TRIES_REMAINING | puk.getTriesRemaining()));
    } else {
        // If we're here, the PUK was correct.
        // Pad the new PIN, if not done by caller. We don't want any gargabe from the APDU buffer to be part of the new PIN.
        Util.arrayFillNonAtomic(buf, (short)(offset_cdata + lc), (short)(PUK_LENGTH + PIN_MAX_LENGTH - lc), (byte) 0x00);

        // Set the PIN.
        pin.update(buf, (short)(offset_cdata+PUK_LENGTH), PIN_MAX_LENGTH);
        pin.resetAndUnblock();
    }
}
 
Example 20
Source File: CardEdge.java    From SatochipApplet with GNU Affero General Public License v3.0 4 votes vote down vote up
/** 
 * This function returns the public key associated with a particular private key stored 
 * in the applet. The exact key blob contents depend on the key�s algorithm and type. 
 * 
 * ins: 0x35
 * p1: private key number (0x00-0x0F)
 * p2: 0x00
 * data: none 
 * return(SECP256K1): [coordx_size(2b) | pubkey_coordx | sig_size(2b) | sig]
 */
private short getPublicKeyFromPrivate(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);
	
	byte key_nb = buffer[ISO7816.OFFSET_P1];
	if ((key_nb < 0) || (key_nb >= MAX_NUM_KEYS))
		ISOException.throwIt(SW_INCORRECT_P1);
	
	Key key = eckeys[key_nb];
	// check type and size
	if ((key == null) || !key.isInitialized())
		ISOException.throwIt(SW_INCORRECT_P1);
	if (key.getType() != KeyBuilder.TYPE_EC_FP_PRIVATE)
		ISOException.throwIt(SW_INCORRECT_ALG);		
	if (key.getSize()!= LENGTH_EC_FP_256)
		ISOException.throwIt(SW_INCORRECT_ALG);
	// check the curve param
	if(!Secp256k1.checkCurveParameters((ECPrivateKey)key, recvBuffer, (short)0))
		ISOException.throwIt(SW_INCORRECT_ALG);
			
	// compute the corresponding partial public key...
       keyAgreement.init((ECPrivateKey)key);
       short coordx_size=(short)32;
   	keyAgreement.generateSecret(Secp256k1.SECP256K1, Secp256k1.OFFSET_SECP256K1_G, (short) 65, buffer, (short)1); //pubkey in uncompressed form
    Util.setShort(buffer, (short)0, coordx_size);
       
       // sign fixed message
       sigECDSA.init(key, 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);
       
       // 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... 
       return (short)(2+coordx_size+2+sign_size);
}