Java Code Examples for javacard.framework.Util#arrayCompare()

The following examples show how to use javacard.framework.Util#arrayCompare() . 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: ECPoint.java    From JCMathLib with MIT License 6 votes vote down vote up
/**
 * Compares this and provided point for equality. The comparison is made using hash of both values to prevent leak of position of mismatching byte.
 * @param other second point for comparison
 * @return true if both point are exactly equal (same length, same value), false otherwise
 */
public boolean isEqual(ECPoint other) {
    boolean bResult = false;
    if (this.length() != other.length()) {
        return false;
    } 
    else {
        // The comparison is made with hash of point values instead of directly values. 
        // This way, offset of first mismatching byte is not leaked via timing side-channel. 
        // Additionally, only single array is required for storage of plain point values thus saving some RAM.            
        ech.lock(ech.uncompressed_point_arr1);
        ech.lock(ech.fnc_isEqual_hashArray);
        //ech.lock(ech.fnc_isEqual_hashEngine);
        short len = this.getW(ech.uncompressed_point_arr1, (short) 0);
        ech.fnc_isEqual_hashEngine.doFinal(ech.uncompressed_point_arr1, (short) 0, len, ech.fnc_isEqual_hashArray, (short) 0);
        len = other.getW(ech.uncompressed_point_arr1, (short) 0);
        len = ech.fnc_isEqual_hashEngine.doFinal(ech.uncompressed_point_arr1, (short) 0, len, ech.uncompressed_point_arr1, (short) 0);
        bResult = Util.arrayCompare(ech.fnc_isEqual_hashArray, (short) 0, ech.uncompressed_point_arr1, (short) 0, len) == 0;
        //ech.unlock(ech.fnc_isEqual_hashEngine);
        ech.unlock(ech.fnc_isEqual_hashArray);
        ech.unlock(ech.uncompressed_point_arr1);
    }

    return bResult;
}
 
Example 2
Source File: FIDOCCImplementation.java    From CCU2F with Apache License 2.0 6 votes vote down vote up
public boolean unwrap(byte[] keyHandle, short keyHandleOffset, short keyHandleLength, byte[] applicationParameter, short applicationParameterOffset, ECPrivateKey unwrappedPrivateKey) {
	
	calcMAC(applicationParameter, applicationParameterOffset, keyHandle, keyHandleOffset);
	
	//Compare MAC
	if (Util.arrayCompare(scratch, (short) 0, keyHandle, (short)(keyHandleOffset+32), (short)32)!=0) {
		return false;
	}
	
	//only get key if signing is required
    if (unwrappedPrivateKey != null) {

    	//Regenerate PrivKey 
    	generatePrivateKey(applicationParameter, applicationParameterOffset, keyHandle, keyHandleOffset);
    	
        unwrappedPrivateKey.setS(scratch, (short)0, (short)32);
    }
    Util.arrayFillNonAtomic(scratch, (short)0, (short)32, (byte)0x00);
    return true;
}
 
Example 3
Source File: OpenPGPSecureMessaging.java    From javacard-openpgpcard with GNU General Public License v2.0 6 votes vote down vote up
/**
 * Set the MAC and encryption (and decryption) session keys. Each key is a 
 * 16 byte 3DES EDE key. This method may be called at any time and will 
 * immediately replace the session key.
 * 
 * @param buffer byte array containing the session keys.
 * @param offset location of the session keys in the buffer.
 */
public void setSessionKeys(byte[] buffer, short offset) {
	// Check for empty keys
	if(Util.arrayCompare(buffer, (short)0, EMPTY_KEY, (short)0, KEY_SIZE) == 0 ||
			Util.arrayCompare(buffer, KEY_SIZE, EMPTY_KEY, (short)0, KEY_SIZE) == 0) {
		keyMAC.clearKey();
		keyENC.clearKey();
	}
	else {    	
		keyMAC.setKey(buffer, offset);
		keyENC.setKey(buffer, (short) (offset + KEY_SIZE));
    
		signer.init(keyMAC, Signature.MODE_SIGN);
    	verifier.init(keyMAC, Signature.MODE_VERIFY);
    
    	cipher.init(keyENC, Cipher.MODE_ENCRYPT);
    	decipher.init(keyENC, Cipher.MODE_DECRYPT);
	}
}
 
Example 4
Source File: Bip32ObjectManager.java    From SatochipApplet with GNU Affero General Public License v3.0 6 votes vote down vote up
/**
 * Creates an object by reserving a fixed memory size for it.
 * Throws a SW_NO_MEMORY_LEFT exception if cannot allocate the memory.
 * 
 * @param src
 *            the source array to copy from
 * @param srcOff
 *            the offset for the source array
 *            
 * @return The memory base address for the object.
 */
public short createObject(byte[] src, short srcOff) {
	if (nb_elem_free == 0)
		ISOException.throwIt(SW_NO_MEMORY_LEFT);		
	
	short base=0;
	while (base<this.size) {
		if (Util.arrayCompare(this.ptr, base, this.empty, (short)0, this.size_id)==0){
			Util.arrayCopyNonAtomic(src, srcOff, this.ptr, base, this.size_elem);
			this.nb_elem_free--;
			this.nb_elem_used++;
			return base;
		}
		base+=this.size_elem;	
	}
	return NULL_OFFSET;//should not happen
}
 
Example 5
Source File: Secp256k1.java    From SatochipApplet with GNU Affero General Public License v3.0 6 votes vote down vote up
public static boolean checkCurveParameters(ECKey eckey, byte[] tmpbuffer, short tmpoffset){
	
	eckey.getA(tmpbuffer, tmpoffset);
	if (0!=Util.arrayCompare(tmpbuffer, tmpoffset, SECP256K1, OFFSET_SECP256K1_a, (short)32))
		return false;
	eckey.getB(tmpbuffer, tmpoffset);
	if (0!=Util.arrayCompare(tmpbuffer, tmpoffset, SECP256K1, OFFSET_SECP256K1_b, (short)32))
		return false;
	eckey.getG(tmpbuffer, tmpoffset);
	if (0!=Util.arrayCompare(tmpbuffer, tmpoffset, SECP256K1, OFFSET_SECP256K1_G, (short)65))
		return false;
	eckey.getR(tmpbuffer, tmpoffset);
	if (0!=Util.arrayCompare(tmpbuffer, tmpoffset, SECP256K1, OFFSET_SECP256K1_R, (short)32))
		return false;
	eckey.getField(tmpbuffer, tmpoffset);
	if (0!=Util.arrayCompare(tmpbuffer, tmpoffset, SECP256K1, OFFSET_SECP256K1_P, (short)32))
		return false;
	if (eckey.getK()!= SECP256K1_K)
		return false;
	
	return true;
}
 
Example 6
Source File: CardEdge.java    From SatochipApplet with GNU Affero General Public License v3.0 5 votes vote down vote up
/**
 * This function allows to reset the 2FA key and disable 2FA.
 * Once activated, 2FA can only be deactivated when the seed is reset and all eckeys cleared.
 *  
 *  ins: 0x78
 *  p1: 0x00
 *  p2: 0x00
 *  data: [hmacsha1_key(20b)]
 *  return: (none)
 */
private short reset2FAKey(APDU apdu, byte[] buffer){
	// check that PIN[0] has been entered previously
	if (!pins[0].isValidated())
		ISOException.throwIt(SW_UNAUTHORIZED);
	
	// check length
	short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]);
	if (bytesLeft < (short)20)
		ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
	
	// reset 2FA can only be done if all private keys are cleared
	if (!needs_2FA)
		ISOException.throwIt(SW_2FA_UNINITIALIZED_KEY);
	if (bip32_seeded)
		ISOException.throwIt(SW_BIP32_INITIALIZED_SEED);
	if (eckeys_flag != 0x0000)
		ISOException.throwIt(SW_ECKEYS_INITIALIZED_KEY);
	
	// compute hmac(2FA_ID) and compare with value provided 
	// hmac of 64-bytes msg: (id_2FA(20b) | 44 bytes 0xAA-padding)
	short offset= ISO7816.OFFSET_CDATA;
	Util.arrayFillNonAtomic(recvBuffer, (short)0, (short)64, (byte)0xAA);
	Util.arrayCopyNonAtomic(data2FA, OFFSET_2FA_ID, recvBuffer, (short)0, (short)20);
	HmacSha160.computeHmacSha160(data2FA, OFFSET_2FA_HMACKEY, (short)20, recvBuffer, (short)0, (short)64, recvBuffer, (short)64);
	if (Util.arrayCompare(buffer, offset, recvBuffer, (short)64, (short)20)!=0)
		ISOException.throwIt(SW_SIGNATURE_INVALID);
	
	// reset flag and data
       needs_2FA= false;	
       key_2FA.clearKey();
       Util.arrayFillNonAtomic(data2FA, (short)0, OFFSET_2FA_SIZE, (byte)0x00);      
       
       return (short)0;
}
 
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 verifyKeyChecksum(byte[] buffer, short offset, short length, byte[] scratch, short scratchOffset) {
    Crypto.digestScratch.doFinal(buffer, offset, (short)(length - 4), scratch, scratchOffset);
    Crypto.digestScratch.doFinal(scratch, scratchOffset, TC.SIZEOF_SHA256, scratch, scratchOffset);
    if (Util.arrayCompare(scratch, scratchOffset, buffer, (short)(offset + length - 4), (short)4) != (byte)0x00) {
        ISOException.throwIt(ISO7816.SW_WRONG_DATA);
    }
}
 
Example 8
Source File: Bip32Cache.java    From ledger-javacard with GNU Affero General Public License v3.0 5 votes vote down vote up
private static Bip32Cache findPath(byte[] path, short pathOffset, byte pathLength, boolean setLast) {
	for (short i=0; i<CACHE_SIZE; i++) {
		if ((cache[i].pathLength == pathLength) &&
			(Util.arrayCompare(path, pathOffset, cache[i].path, (short)0, (short)(pathLength * 4)) == 0)) {
				if (setLast) {
					lastCacheIndex[0] = (byte)i;
				}
				return cache[i];
		}
	}
	return null;
}
 
Example 9
Source File: Bip32ObjectManager.java    From SatochipApplet with GNU Affero General Public License v3.0 5 votes vote down vote up
/**
1 * Returns the object base address (offset) for an object that start with data provided in array
 * <p>
 * 
 * @param src
 *            a byte array to compare object with
 * @param srcOff
 *            the offset for the source array
 */
public short getBaseAddress(byte[] src, short srcOff) {
	short base = 0;
	while (base<this.size) {
		if (Util.arrayCompare(src, srcOff, this.ptr, base, this.size_id)==0){
			return base;
		}
		base+=this.size_elem;
	}
	return NULL_OFFSET;
}
 
Example 10
Source File: Bip32ObjectManager.java    From SatochipApplet with GNU Affero General Public License v3.0 5 votes vote down vote up
public short reset(){
	short base = 0;
	short nb_deleted=0;
	while (base<this.size) {
		if (Util.arrayCompare(this.ptr, base, this.empty, (short)0, this.size_id)!=0){
			Util.arrayFillNonAtomic(this.ptr, base, this.size_elem, (byte)0x00);
			this.nb_elem_free++;
			this.nb_elem_used--;
			nb_deleted++;
		}
		base+=this.size_elem;
	}
	return nb_deleted;
}
 
Example 11
Source File: Bip32ObjectManager.java    From SatochipApplet with GNU Affero General Public License v3.0 5 votes vote down vote up
/**
 * Destroy the object starting with specific value
 * 
 * @param src
 *            a byte array to compare object with
 * @param srcOff
 *            the offset for the source array
 */
public void destroyObject(byte[] src, short srcOff){
	short base = 0;
	while (base<this.size) {
		if (Util.arrayCompare(src, srcOff, this.ptr, base, this.size_id)==0){
			Util.arrayFillNonAtomic(this.ptr, base, this.size_elem, (byte)0x00);
			this.nb_elem_free++;
			this.nb_elem_used--;
			return;
		}
		base+=this.size_elem;
	}	
}
 
Example 12
Source File: Bignat.java    From JCMathLib with MIT License 5 votes vote down vote up
/**
 * Equality check. Requires that this object and other have the same size or are padded with zeroes.
 * Returns true if all digits (except for leading zeroes) are equal.
 *
 *
 * @param other Bignat to compare
 * @return true if this and other have the same value, false otherwise.
 */
public boolean same_value(Bignat other) { 
    short hashLen;
    // Compare using hash engine
    // The comparison is made with hash of point values instead of directly values. 
    // This way, offset of first mismatching byte is not leaked via timing side-channel. 
    bnh.lock(bnh.fnc_same_value_array1);
    bnh.lock(bnh.fnc_same_value_hash);
    if (this.length() == other.length()) {
        // Same length, we can hash directly from BN values
        bnh.hashEngine.doFinal(this.value, (short) 0, this.length(), bnh.fnc_same_value_hash, (short) 0);
        hashLen = bnh.hashEngine.doFinal(other.value, (short) 0, other.length(), bnh.fnc_same_value_array1, (short) 0);
    }
    else {
        // Different length of bignats - can be still same if prepended with zeroes 
        // Find the length of longer one and padd other one with starting zeroes
        if (this.length() < other.length()) {
            this.prepend_zeros(other.length(), bnh.fnc_same_value_array1, (short) 0);
            bnh.hashEngine.doFinal(bnh.fnc_same_value_array1, (short) 0, other.length(), bnh.fnc_same_value_hash, (short) 0);
            hashLen = bnh.hashEngine.doFinal(other.value, (short) 0, other.length(), bnh.fnc_same_value_array1, (short) 0);
        }
        else {
            other.prepend_zeros(this.length(), bnh.fnc_same_value_array1, (short) 0);
            bnh.hashEngine.doFinal(bnh.fnc_same_value_array1, (short) 0, this.length(), bnh.fnc_same_value_hash, (short) 0);
            hashLen = bnh.hashEngine.doFinal(this.value, (short) 0, this.length(), bnh.fnc_same_value_array1, (short) 0);
        }
    }

    boolean bResult = Util.arrayCompare(bnh.fnc_same_value_hash, (short) 0, bnh.fnc_same_value_array1, (short) 0, hashLen) == 0;

    bnh.unlock(bnh.fnc_same_value_array1);
    bnh.unlock(bnh.fnc_same_value_hash);

    return bResult;
}
 
Example 13
Source File: OpenPGPSecureMessaging.java    From javacard-openpgpcard with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Set the encryption session key. Each key is a 16 byte 3DES EDE key. This method 
 * may be called at any time and will immediately replace the session key.
 * 
 * @param buffer byte array containing the session key.
 * @param offset location of the session key in the buffer.
 */
public void setSessionKeyEncryption(byte[] buffer, short offset) {
	// Check for empty keys
	if(Util.arrayCompare(buffer, (short)0, EMPTY_KEY, (short)0, KEY_SIZE) == 0) {
		keyMAC.clearKey();
		keyENC.clearKey();
	}
	else {     	
		keyENC.setKey(buffer, (short) (offset + KEY_SIZE));
    
		cipher.init(keyENC, Cipher.MODE_ENCRYPT);
		decipher.init(keyENC, Cipher.MODE_DECRYPT);
	}
}
 
Example 14
Source File: OpenPGPSecureMessaging.java    From javacard-openpgpcard with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Set the MAC session key. Each key is a 16 byte 3DES EDE key. This method 
 * may be called at any time and will immediately replace the session key.
 * 
 * @param buffer byte array containing the session key.
 * @param offset location of the session key in the buffer.
 */
public void setSessionKeyMAC(byte[] buffer, short offset) {
	// Check for empty keys
	if(Util.arrayCompare(buffer, (short)0, EMPTY_KEY, (short)0, KEY_SIZE) == 0) {
		keyMAC.clearKey();
		keyENC.clearKey();
	}
	else {     	
		keyMAC.setKey(buffer, offset);
    
		signer.init(keyMAC, Signature.MODE_SIGN);
		verifier.init(keyMAC, Signature.MODE_VERIFY);
	}
}
 
Example 15
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 16
Source File: CardEdge.java    From SatochipApplet with GNU Affero General Public License v3.0 4 votes vote down vote up
/**
   * This function signs a given transaction hash with a std or the last extended key
   * If 2FA is enabled, a HMAC must be provided as an additional security layer. 
* 
   * ins: 0x7A
* p1: key number or 0xFF for the last derived Bip32 extended key  
* p2: 0x00
* data: [hash(32b) | option: 2FA-flag(2b)|hmac(20b)]
* 
* return: [sig ]
* 
   */
  private short SignTransactionHash(APDU apdu, byte[] buffer){
  	
  	// check that PIN[0] has been entered previously
if (!pins[0].isValidated())
	ISOException.throwIt(SW_UNAUTHORIZED);

  	byte key_nb = buffer[ISO7816.OFFSET_P1];
if ( (key_nb!=(byte)0xFF) && ((key_nb < 0) || (key_nb >= MAX_NUM_KEYS)) )
	ISOException.throwIt(SW_INCORRECT_P1);

  	short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]);
if (bytesLeft<MessageDigest.LENGTH_SHA_256)
	ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
  	
  	// check whether the seed is initialized
if (key_nb==(byte)0xFF && !bip32_seeded)
	ISOException.throwIt(SW_BIP32_UNINITIALIZED_SEED);
  	
// check 2FA if required
if(needs_2FA){
	// check data length
	if (bytesLeft<MessageDigest.LENGTH_SHA_256+MessageDigest.LENGTH_SHA+(short)2)
		ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
	// check flag for 2fa_hmac_chalresp
	short hmac_flags= Util.getShort(buffer, (short)(ISO7816.OFFSET_CDATA+32));
	if (hmac_flags!=HMAC_CHALRESP_2FA)
		ISOException.throwIt(SW_INCORRECT_ALG);
	// hmac of 64-bytes msg: ( 32bytes tx_hash | 32bytes 0xCC-padding)
	Util.arrayCopyNonAtomic(buffer, (short)ISO7816.OFFSET_CDATA, recvBuffer, (short)0, (short)32);
	Util.arrayFillNonAtomic(recvBuffer, (short)32, (short)32, (byte)0xCC);
	HmacSha160.computeHmacSha160(data2FA, OFFSET_2FA_HMACKEY, (short)20, recvBuffer, (short)0, (short)64, recvBuffer, (short)64);
	if (Util.arrayCompare(buffer, (short)(ISO7816.OFFSET_CDATA+32+2), recvBuffer, (short)64, (short)20)!=0)
		ISOException.throwIt(SW_SIGNATURE_INVALID);
}

// hash+sign singlehash
  	if (key_nb==(byte)0xFF)
  		sigECDSA.init(bip32_extendedkey, Signature.MODE_SIGN);
  	else{
  		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);
  		sigECDSA.init(key, Signature.MODE_SIGN);
  	}
      short sign_size= sigECDSA.signPreComputedHash(buffer, ISO7816.OFFSET_CDATA, MessageDigest.LENGTH_SHA_256, buffer, (short)0);
      return sign_size;
  }
 
Example 17
Source File: CardEdge.java    From SatochipApplet with GNU Affero General Public License v3.0 4 votes vote down vote up
/**
   * This function signs the current hash transaction with a std or the last extended key
   * The hash provided in the APDU is compared to the version stored inside the chip.
* Depending of the total amount in the transaction and the predefined limit, 
* a HMAC must be provided as an additional security layer. 
* 
   * ins: 0x6F
* p1: key number or 0xFF for the last derived Bip32 extended key  
* p2: 0x00
* data: [hash(32b) | option: 2FA-flag(2b)|hmac(20b)]
* 
* return: [sig ]
*
   */
  private short SignTransaction(APDU apdu, byte[] buffer){
// check that PIN[0] has been entered previously
if (!pins[0].isValidated())
	ISOException.throwIt(SW_UNAUTHORIZED);

  	byte key_nb = buffer[ISO7816.OFFSET_P1];
if ( (key_nb!=(byte)0xFF) && ((key_nb < 0) || (key_nb >= MAX_NUM_KEYS)) )
	ISOException.throwIt(SW_INCORRECT_P1);

  	short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]);
if (bytesLeft<MessageDigest.LENGTH_SHA_256)
	ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
  	
  	// check whether the seed is initialized
if (key_nb==(byte)0xFF && !bip32_seeded)
	ISOException.throwIt(SW_BIP32_UNINITIALIZED_SEED);

// check doublehash value in buffer with cached singlehash value
sha256.reset();
sha256.doFinal(transactionData, OFFSET_TRANSACTION_HASH, MessageDigest.LENGTH_SHA_256, recvBuffer, (short)0);
if ((byte)0 != Util.arrayCompare(buffer, ISO7816.OFFSET_CDATA, recvBuffer, (short)0, MessageDigest.LENGTH_SHA_256))
	ISOException.throwIt(SW_INCORRECT_TXHASH);

// check challenge-response answer if necessary
if(needs_2FA){
	if(	Biginteger.lessThan(data2FA, OFFSET_2FA_LIMIT, transactionData, OFFSET_TRANSACTION_AMOUNT, (short)8)){
		if (bytesLeft<MessageDigest.LENGTH_SHA_256+MessageDigest.LENGTH_SHA+(short)2)
			ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
		// check flag for 2fa_hmac_chalresp
		short hmac_flags= Util.getShort(buffer, (short)(ISO7816.OFFSET_CDATA+32));
		if (hmac_flags!=HMAC_CHALRESP_2FA)
			ISOException.throwIt(SW_INCORRECT_ALG);
		// hmac of 64-bytes msg: (doublesha256(raw_tx) | 32bytes zero-padding)
		Util.arrayFillNonAtomic(recvBuffer, (short)32, (short)32, (byte)0x00);
		HmacSha160.computeHmacSha160(data2FA, OFFSET_2FA_HMACKEY, (short)20, recvBuffer, (short)0, (short)64, recvBuffer, (short)64);
		if (Util.arrayCompare(buffer, (short)(ISO7816.OFFSET_CDATA+32+2), recvBuffer, (short)64, (short)20)!=0)
			ISOException.throwIt(SW_SIGNATURE_INVALID);
		// reset total amount
		Util.arrayFillNonAtomic(transactionData, OFFSET_TRANSACTION_TOTAL, (short)8, (byte)0x00);
	}
	else{					
		//update total amount
		Util.arrayCopyNonAtomic(transactionData, OFFSET_TRANSACTION_AMOUNT, transactionData, OFFSET_TRANSACTION_TOTAL, (short)8);
	}
}

// hash+sign singlehash
  	if (key_nb==(byte)0xFF)
  		sigECDSA.init(bip32_extendedkey, Signature.MODE_SIGN);
  	else{
  		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);
  		sigECDSA.init(key, Signature.MODE_SIGN);
  	}
      short sign_size= sigECDSA.sign(transactionData, OFFSET_TRANSACTION_HASH, (short)32, buffer, (short)0);
      return 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 resets the Bip32 seed and all derived keys: the master key, chain code, authentikey 
 * and the 32-bit AES key that is used to encrypt/decrypt Bip32 object stored in secure memory.
 * If 2FA is enabled, then a hmac code must be provided, based on the 4-byte counter-2FA.
 *  
 *  ins: 0x77
 *  p1: PIN_size 
 *  p2: 0x00
 *  data: [PIN | optional-hmac(20b)]
 *  return: (none)
 */
private short resetBIP32Seed(APDU apdu, byte[] buffer){
	
	short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]);
	
	// check provided PIN
	byte pin_size= buffer[ISO7816.OFFSET_P1];
	OwnerPIN pin = pins[(byte)0x00];
	if (bytesLeft < pin_size)
		ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
	if (!CheckPINPolicy(buffer, ISO7816.OFFSET_CDATA, 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, (byte) pin_size)) {
		LogoutIdentity((byte)0x00);
		ISOException.throwIt((short)(SW_PIN_FAILED + triesRemaining - 1));
	}
	
	// check if seeded
	if (!bip32_seeded)
		ISOException.throwIt(SW_BIP32_UNINITIALIZED_SEED);
	
	// check 2FA if required
	if (needs_2FA){
		short offset= Util.makeShort((byte)0, ISO7816.OFFSET_CDATA);
		offset+=pin_size;
		bytesLeft-= pin_size;
		if (bytesLeft < (short)20)
			ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
		
		// compute hmac(counter_2FA) and compare with value provided 
		// hmac of 64-bytes msg: ( authentikey-coordx(32b) | 32bytes 0xFF-padding)
		Util.arrayFillNonAtomic(recvBuffer, (short)0, (short)64, (byte)0xFF);
		Util.arrayCopyNonAtomic(authentikey_pubkey, (short)0x01, recvBuffer, (short)0, BIP32_KEY_SIZE);
		HmacSha160.computeHmacSha160(data2FA, OFFSET_2FA_HMACKEY, (short)20, recvBuffer, (short)0, (short)64, recvBuffer, (short)64);
		if (Util.arrayCompare(buffer, offset, recvBuffer, (short)64, (short)20)!=0)
			ISOException.throwIt(SW_SIGNATURE_INVALID);
	}		
	// reset memory cache, bip32 flag and all data!
	bip32_om.reset();
	bip32_seeded= false;
	bip32_masterkey.clearKey(); 
	bip32_masterchaincode.clearKey();
	bip32_encryptkey.clearKey();
	bip32_authentikey.clearKey();
	Secp256k1.setCommonCurveParameters(bip32_authentikey);// keep public params!
	Util.arrayFillNonAtomic(authentikey_pubkey, (short)0, (short)(2*BIP32_KEY_SIZE+1), (byte)0x00);
	LogOutAll();
	return (short)0;
}
 
Example 19
Source File: CardEdge.java    From SatochipApplet with GNU Affero General Public License v3.0 4 votes vote down vote up
/** 
 * This function allows to reset a private ECkey stored in the card.
 * If 2FA is enabled, a hmac code must be provided to reset the key.
 * 
 * ins: 0x33
 * p1: private key number (0x00-0x0F)
 * p2: 0x00
 * data: [ (option)HMAC-2FA(20b)] 
 * return: none
 */
private short ResetKey(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);
	
	// check 2FA if required
	if (needs_2FA){
		short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]);
		
		if (bytesLeft < (short)20)
			ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
		
		// compute the corresponding partial public key...
		keyAgreement.init((ECPrivateKey)key);
		keyAgreement.generateSecret(Secp256k1.SECP256K1, Secp256k1.OFFSET_SECP256K1_G, (short) 65, tmpBuffer, (short)0); //pubkey in uncompressed form
		Util.arrayCopy(tmpBuffer, (short)1, recvBuffer, (short)0, (short)32);
		// hmac of 64-bytes msg: (pubkey-x | 32bytes (0x20^key_nb)-padding)
		Util.arrayFillNonAtomic(recvBuffer, (short)32, (short)32, (byte) (0x20^key_nb));
		HmacSha160.computeHmacSha160(data2FA, OFFSET_2FA_HMACKEY, (short)20, recvBuffer, (short)0, (short)64, recvBuffer, (short)64);
		if (Util.arrayCompare(buffer, ISO7816.OFFSET_CDATA, recvBuffer, (short)64, (short)20)!=0)
			ISOException.throwIt(SW_SIGNATURE_INVALID);			
	}
	
	// clear key & reset flag
	key.clearKey();
	eckeys_flag &= (short) ~(0x0001 << key_nb);// reset corresponding bit flag;
	
	return (short)0;
}
 
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 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);
    }
}