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 vote down vote up
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 vote down vote up
/**
 * \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 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 4
Source File: LedgerWalletApplet.java    From ledger-javacard with GNU Affero General Public License v3.0 5 votes vote down vote up
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 vote down vote up
/**
 * 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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
/**
	 * 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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
/**
 * 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 vote down vote up
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 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 16
Source File: Gpg.java    From OpenPGP-Card with GNU General Public License v3.0 4 votes vote down vote up
/**
 * 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 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 18
Source File: CardEdge.java    From SatochipApplet with GNU Affero General Public License v3.0 4 votes vote down vote up
/** 
 * 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 vote down vote up
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 vote down vote up
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);
    }
}