javacardx.crypto.Cipher Java Examples

The following examples show how to use javacardx.crypto.Cipher. 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: Gpg.java    From OpenPGP-Card with GNU General Public License v3.0 7 votes vote down vote up
private void internalAuthenticate(APDU apdu) {
  byte[] buffer = apdu.getBuffer();
  // PW1 with 0x82
  if (!pins[PIN_INDEX_PW1].isValidated() || !pinSubmitted[1]) {
    ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
  }
  short len = apdu.setIncomingAndReceive();
  if (len > (short) 102 || len != (buffer[ISO7816.OFFSET_LC] & 0xFF)) {
    ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
  }
  if (!authenticationKey.getPrivate().isInitialized()) {
    ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND);
  }
  cipherRSA.init(authenticationKey.getPrivate(), Cipher.MODE_ENCRYPT);
  cipherRSA.doFinal(buffer, ISO7816.OFFSET_CDATA, len, buffer, (short) 0);
  apdu.setOutgoingAndSend((short) 0, RSA_KEY_LENGTH_BYTES);
}
 
Example #2
Source File: Bignat.java    From JCMathLib with MIT License 6 votes vote down vote up
/**
 * Calculates {@code res := base ** exp mod mod} using RSA engine. 
 * Requirements:
 * 1. Modulo must be either 521, 1024, 2048 or other lengths supported by RSA (see appendzeros() and mod() method)
 * 2. Base must have the same size as modulo (see prependzeros())
 * @param baseLen   length of base rounded to size of RSA engine
 * @param base      value of base (if size is not equal to baseLen then zeroes are appended)
 * @param exponent  array with exponent
 * @param exponentLen length of exponent
 * @param modulo    value of modulo 
 * @param resultArray array for the computed result
 * @param resultOffset start offset of resultArray
 */
private short n_mod_exp(short baseLen, Bignat base, byte[] exponent, short exponentLen, Bignat modulo, byte[] resultArray, short resultOffset) {
    // Verify if pre-allocated engine match the required values
    if (bnh.fnc_NmodE_pubKey.getSize() < (short) (modulo.length() * 8)) {
        // attempt to perform modulu with higher or smaller than supported length - try change constant MODULO_ENGINE_MAX_LENGTH
        ISOException.throwIt(ReturnCodes.SW_BIGNAT_MODULOTOOLARGE);
    }
    if (bnh.fnc_NmodE_pubKey.getSize() < (short) (base.length() * 8)) {
        ISOException.throwIt(ReturnCodes.SW_BIGNAT_MODULOTOOLARGE);
    }
    // Potential problem: we are changing key value for publicKey already used before with occ.bnHelper.modCipher. 
    // Simulator and potentially some cards fail to initialize this new value properly (probably assuming that same key object will always have same value)
    // Fix (if problem occure): generate new key object: RSAPublicKey publicKey = (RSAPublicKey) KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PUBLIC, (short) (baseLen * 8), false);

    bnh.fnc_NmodE_pubKey.setExponent(exponent, (short) 0, exponentLen);
    bnh.lock(bnh.fnc_deep_resize_tmp);
    modulo.append_zeros(baseLen, bnh.fnc_deep_resize_tmp, (short) 0);
    bnh.fnc_NmodE_pubKey.setModulus(bnh.fnc_deep_resize_tmp, (short) 0, baseLen);
    bnh.fnc_NmodE_cipher.init(bnh.fnc_NmodE_pubKey, Cipher.MODE_DECRYPT);        
    base.prepend_zeros(baseLen, bnh.fnc_deep_resize_tmp, (short) 0);
    // BUGBUG: Check if input is not all zeroes (causes out-of-bound exception on some cards)
    short len = bnh.fnc_NmodE_cipher.doFinal(bnh.fnc_deep_resize_tmp, (short) 0, baseLen, resultArray, resultOffset); 
    bnh.unlock(bnh.fnc_deep_resize_tmp);
    return len;
}
 
Example #3
Source File: FIDOStandalone.java    From ledger-u2f-javacard with Apache License 2.0 6 votes vote down vote up
/**
 * Init cipher engines and allocate memory.
 */
public FIDOStandalone() {
    scratch = JCSystem.makeTransientByteArray((short) 64, JCSystem.CLEAR_ON_DESELECT);
    keyPair = new KeyPair(
    (ECPublicKey) KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PUBLIC, KeyBuilder.LENGTH_EC_FP_256, false),
    (ECPrivateKey) KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PRIVATE, KeyBuilder.LENGTH_EC_FP_256, false));
    Secp256r1.setCommonCurveParameters((ECKey) keyPair.getPrivate());
    Secp256r1.setCommonCurveParameters((ECKey) keyPair.getPublic());
    random = RandomData.getInstance(RandomData.ALG_KEYGENERATION);
    // Initialize the unique wrapping key
    chipKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_256, false);
    random.nextBytes(scratch, (short) 0, (short) 32);
    chipKey.setKey(scratch, (short) 0);
    cipherEncrypt = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false);
    cipherEncrypt.init(chipKey, Cipher.MODE_ENCRYPT, IV_ZERO_AES, (short) 0, (short) IV_ZERO_AES.length);
    cipherDecrypt = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false);
    cipherDecrypt.init(chipKey, Cipher.MODE_DECRYPT, IV_ZERO_AES, (short) 0, (short) IV_ZERO_AES.length);
}
 
Example #4
Source File: GidsBaseTestClass.java    From GidsApplet with GNU General Public License v3.0 6 votes vote down vote up
protected void authenticateGeneral(byte[] key, boolean successexpected) {
    byte[] challenge, challengeresponse = new byte[8];
    Cipher cipherDES = Cipher.getInstance(Cipher.ALG_DES_CBC_NOPAD, false);
    DESKey deskey = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES, KeyBuilder.LENGTH_DES3_3KEY, false);
    deskey.setKey(key, (short) 0);

    // select admin key
    execute("00 22 81 A4 03 83 01 80");
    // get a challenge
    ResponseAPDU response = execute("00 87 00 00 04 7C 02 81 00 00");
    if (!Arrays.equals(Arrays.copyOfRange(response.getBytes(), 0, 4), new byte[] {0x7C,0x0A,(byte) 0x81,0x08})) {
        fail("not a challenge:" + DatatypeConverter.printHexBinary(response.getBytes()));
    }
    // compute the response
    challenge = Arrays.copyOfRange(response.getBytes(), 4, 12);
    //solve challenge
    cipherDES.init(deskey, Cipher.MODE_ENCRYPT);
    cipherDES.doFinal(challenge, (short) 0, (short)8, challengeresponse, (short) 0);
    // send the response
    execute("00 87 00 00 0C 7C 0A 82 08" + DatatypeConverter.printHexBinary(challengeresponse), (successexpected?0x9000: 0x6982));
}
 
Example #5
Source File: PinTests.java    From GidsApplet with GNU General Public License v3.0 6 votes vote down vote up
@Test
public void authenticateGeneralReplayAttack() {
    byte[] challenge, challengeresponse = new byte[8];
    byte[] key = DatatypeConverter.parseHexBinary("010203040506070801020304050607080102030405060708");
    Cipher cipherDES = Cipher.getInstance(Cipher.ALG_DES_CBC_NOPAD, false);
    DESKey deskey = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES, KeyBuilder.LENGTH_DES3_3KEY, false);
    deskey.setKey(key, (short) 0);

    // select admin key
    execute("00 22 81 A4 03 83 01 80");
    // get a challenge
    ResponseAPDU response = execute("00 87 00 00 04 7C 02 81 00 00");
    if (!Arrays.equals(Arrays.copyOfRange(response.getBytes(), 0, 4), new byte[] {0x7C,0x0A,(byte) 0x81,0x08})) {
        fail("not a challenge:" + DatatypeConverter.printHexBinary(response.getBytes()));
    }
    // compute the response
    challenge = Arrays.copyOfRange(response.getBytes(), 4, 12);
    //solve challenge
    cipherDES.init(deskey, Cipher.MODE_ENCRYPT);
    cipherDES.doFinal(challenge, (short) 0, (short)8, challengeresponse, (short) 0);
    // send the response
    execute("00 87 00 00 0C 7C 0A 82 08" + DatatypeConverter.printHexBinary(challengeresponse), 0x9000);
    execute("00 87 00 00 0C 7C 0A 82 08" + DatatypeConverter.printHexBinary(challengeresponse), 0x6985);
}
 
Example #6
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 #7
Source File: OpenPGPSecureMessaging.java    From javacard-openpgpcard with GNU General Public License v2.0 6 votes vote down vote up
/**
 * Construct a new secure messaging wrapper.
 */
public OpenPGPSecureMessaging() {
    ssc = JCSystem.makeTransientByteArray(SSC_SIZE, 
            JCSystem.CLEAR_ON_DESELECT);
    tmp = JCSystem.makeTransientByteArray(TMP_SIZE, 
            JCSystem.CLEAR_ON_DESELECT);
    signer = Signature.getInstance(
            Signature.ALG_DES_MAC8_ISO9797_1_M2_ALG3, false);
    verifier = Signature.getInstance(
            Signature.ALG_DES_MAC8_ISO9797_1_M2_ALG3, false);
    cipher = Cipher.getInstance(
            Cipher.ALG_DES_CBC_ISO9797_M2, false);
    decipher = Cipher.getInstance(
            Cipher.ALG_DES_CBC_ISO9797_M2, false);
    
    keyMAC = (DESKey) KeyBuilder.buildKey(
            KeyBuilder.TYPE_DES_TRANSIENT_DESELECT, 
            KeyBuilder.LENGTH_DES3_2KEY, false);
    keyENC = (DESKey) KeyBuilder.buildKey(
            KeyBuilder.TYPE_DES_TRANSIENT_DESELECT, 
            KeyBuilder.LENGTH_DES3_2KEY, false);
    
    ssc_set = JCSystem.makeTransientBooleanArray((short)1, JCSystem.CLEAR_ON_DESELECT);
    ssc_set[0] = false;
}
 
Example #8
Source File: Crypto.java    From status-keycard with Apache License 2.0 6 votes vote down vote up
Crypto() {
  random = RandomData.getInstance(RandomData.ALG_SECURE_RANDOM);
  sha256 = MessageDigest.getInstance(MessageDigest.ALG_SHA_256, false);
  ecdh = KeyAgreement.getInstance(KeyAgreement.ALG_EC_SVDP_DH_PLAIN, false);
  sha512 = MessageDigest.getInstance(MessageDigest.ALG_SHA_512, false);
  aesCbcIso9797m2 = Cipher.getInstance(Cipher.ALG_AES_CBC_ISO9797_M2,false);

  try {
    hmacSHA512 = Signature.getInstance(Signature.ALG_HMAC_SHA_512, false);
    hmacKey = (HMACKey) KeyBuilder.buildKey(KeyBuilder.TYPE_HMAC_TRANSIENT_DESELECT, KeyBuilder.LENGTH_AES_256, false);
  } catch (CryptoException e) {
    hmacSHA512 = null;
    hmacBlock = JCSystem.makeTransientByteArray(HMAC_BLOCK_SIZE, JCSystem.CLEAR_ON_RESET);
  }

}
 
Example #9
Source File: SecureChannel.java    From status-keycard with Apache License 2.0 6 votes vote down vote up
/**
 * Decrypts the given APDU buffer. The plaintext is written in-place starting at the ISO7816.OFFSET_CDATA offset. The
 * MAC and padding are stripped. The LC byte is overwritten with the plaintext length. If the MAC cannot be verified
 * the secure channel is reset and the SW 0x6982 is thrown.
 *
 * @param apduBuffer the APDU buffer
 * @return the length of the decrypted
 */
public short preprocessAPDU(byte[] apduBuffer) {
  if (!isOpen()) {
    ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
  }

  short apduLen = (short)((short) apduBuffer[ISO7816.OFFSET_LC] & 0xff);

  if (!verifyAESMAC(apduBuffer, apduLen)) {
    reset();
    ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
  }

  crypto.aesCbcIso9797m2.init(scEncKey, Cipher.MODE_DECRYPT, secret, (short) 0, SC_BLOCK_SIZE);
  Util.arrayCopyNonAtomic(apduBuffer, ISO7816.OFFSET_CDATA, secret, (short) 0, SC_BLOCK_SIZE);
  short len = crypto.aesCbcIso9797m2.doFinal(apduBuffer, (short)(ISO7816.OFFSET_CDATA + SC_BLOCK_SIZE), (short) (apduLen - SC_BLOCK_SIZE), apduBuffer, ISO7816.OFFSET_CDATA);

  apduBuffer[ISO7816.OFFSET_LC] = (byte) len;

  return len;
}
 
Example #10
Source File: SecureChannel.java    From status-keycard with Apache License 2.0 6 votes vote down vote up
/**
 * Decrypts the content of the APDU by generating an AES key using EC-DH. Usable only with specific commands.
 * @param apduBuffer the APDU buffer
 */
public void oneShotDecrypt(byte[] apduBuffer) {
  crypto.ecdh.init(scKeypair.getPrivate());

  short off = (short)(ISO7816.OFFSET_CDATA + 1);
  try {
    crypto.ecdh.generateSecret(apduBuffer, off, apduBuffer[ISO7816.OFFSET_CDATA], secret, (short) 0);
    off = (short)(off + apduBuffer[ISO7816.OFFSET_CDATA]);
  } catch(Exception e) {
    ISOException.throwIt(ISO7816.SW_WRONG_DATA);
    return;
  }

  scEncKey.setKey(secret, (short) 0);
  crypto.aesCbcIso9797m2.init(scEncKey, Cipher.MODE_DECRYPT, apduBuffer, off, SC_BLOCK_SIZE);
  off = (short)(off + SC_BLOCK_SIZE);

  apduBuffer[ISO7816.OFFSET_LC] = (byte) crypto.aesCbcIso9797m2.doFinal(apduBuffer, off, (short)((short)(apduBuffer[ISO7816.OFFSET_LC] & 0xff) - off + ISO7816.OFFSET_CDATA), apduBuffer, ISO7816.OFFSET_CDATA);
}
 
Example #11
Source File: GaussKeyCard.java    From gauss-key-card with Apache License 2.0 6 votes vote down vote up
private void
processAuthenticate(APDU apdu)
{
	final byte[] buffer = apdu.getBuffer();
	final short incomingLength = (short) (buffer[ISO7816.OFFSET_LC] & 0x00FF);

	if (incomingLength < (short)0x51) {
		ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
	}

	ecdh.generateSecret(buffer, ISO7816.OFFSET_CDATA, (short)65, buffer, (short)16);

	aes_key.setKey(buffer, (short)16);
	aes_ecb.init(aes_key, Cipher.MODE_ENCRYPT);

	// Generate the random salt.
	rng.generateData(buffer, OFFSET_CHALLENGE, (short)4);

	short len = aes_ecb.doFinal(buffer, OFFSET_CHALLENGE, (short)16, buffer, (short)0);
	final short le = apdu.setOutgoing();

	len = le > 0 ? (le > len ? len : le) : len;
	apdu.setOutgoingLength(len);
	apdu.sendBytes((short)0, len);
}
 
Example #12
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 #13
Source File: Gpg.java    From OpenPGP-Card with GNU General Public License v3.0 5 votes vote down vote up
private void computeSignature(APDU apdu) {
  byte[] buffer = apdu.getBuffer();
  short length = (short) (buffer[ISO7816.OFFSET_LC] & 0x00FF);
  // Make sure that DigestInfo is <= 40% of the RSA key length.
  if ((short) (length * 4) > (short) (RSA_KEY_LENGTH_BYTES * 10) ||
      apdu.setIncomingAndReceive() != length) {
    ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
  }
  if (!pinSubmitted[PIN_INDEX_PW1] || !pins[PIN_INDEX_PW1].isValidated()) {
    ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
  }
  if (!signatureKey.getPrivate().isInitialized()) {
    ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND);
  }
  if (pinValidForMultipleSignatures == (byte) 0) {
    pinSubmitted[PIN_INDEX_PW1] = false;
  }

  cipherRSA.init(signatureKey.getPrivate(), Cipher.MODE_ENCRYPT);
  cipherRSA.doFinal(buffer, ISO7816.OFFSET_CDATA, length, buffer, (short) 0);
  JCSystem.beginTransaction();
  if (signatureCounter[2] != (byte) 0xFF) {
    signatureCounter[2] = (byte) ((signatureCounter[2] & 0xFF) + 1);
  } else {
    signatureCounter[2] = 0;
    if (signatureCounter[1] != (byte) 0xFF) {
      signatureCounter[1] = (byte) ((signatureCounter[1] & 0xFF) + 1);
    } else if (signatureCounter[0] != (byte) 0xFF) {
      signatureCounter[1] = 0;
      signatureCounter[0] = (byte) ((signatureCounter[0] & 0xFF) + 1);
    } else {
      JCSystem.abortTransaction();
      ISOException.throwIt(ISO7816.SW_FILE_FULL);
    }
  }
  JCSystem.commitTransaction();
  apdu.setOutgoingAndSend((short) 0, RSA_KEY_LENGTH_BYTES);
}
 
Example #14
Source File: PinTests.java    From GidsApplet with GNU General Public License v3.0 5 votes vote down vote up
@Test
public void authenticateMutualReplayAttack() {
    byte[] key = DatatypeConverter.parseHexBinary("010203040506070801020304050607080102030405060708");
    byte[] myChallenge= new byte [16], globalchallenge = new byte[40], challengeresponse = new byte[40];
    byte[] challenge;
    Cipher cipherDES = Cipher.getInstance(Cipher.ALG_DES_CBC_NOPAD, false);
    DESKey deskey = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES, KeyBuilder.LENGTH_DES3_3KEY, false);
    deskey.setKey(key, (short) 0);
    RandomData randomData = RandomData.getInstance(RandomData.ALG_SECURE_RANDOM);
    randomData.generateData(myChallenge, (short) 0, (short) myChallenge.length);
    // select admin key
    execute("00 22 81 A4 03 83 01 80");
    // get a challenge
    ResponseAPDU response = execute("00 87 00 00 14 7C 12 81 10" + DatatypeConverter.printHexBinary(myChallenge) + "00");
    if (!Arrays.equals(Arrays.copyOfRange(response.getBytes(), 0, 4), new byte[] {0x7C,0x12,(byte) 0x81,0x10})) {
        fail("not a challenge:" + DatatypeConverter.printHexBinary(response.getBytes()));
    }
    // compute the response
    challenge = Arrays.copyOfRange(response.getBytes(), 4, 20);
    //solve challenge
    //R2
    System.arraycopy(challenge, 0, globalchallenge, 0, 16);
    //R1
    System.arraycopy(myChallenge, 0, globalchallenge, 16, 16);
    // keep Z1 random
    globalchallenge[(short)39] = (byte) 0x80;
    cipherDES.init(deskey, Cipher.MODE_ENCRYPT);
    cipherDES.doFinal(globalchallenge, (short) 0, (short)40, challengeresponse, (short) 0);
    // send the response
    execute("00 87 00 00 2C 7C 2A 82 28" + DatatypeConverter.printHexBinary(challengeresponse), 0x9000);
    execute("00 87 00 00 2C 7C 2A 82 28" + DatatypeConverter.printHexBinary(challengeresponse), 0x6985);
}
 
Example #15
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 #16
Source File: Gpg.java    From OpenPGP-Card with GNU General Public License v3.0 4 votes vote down vote up
private void decrypt(APDU apdu) {
  byte[] buffer = apdu.getBuffer();
  // PW1 with 0x82
  if (!pins[PIN_INDEX_PW1].isValidated() || !pinSubmitted[1]) {
    ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
  }
  if (!confidentialityKey.getPrivate().isInitialized()) {
    ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND);
  }
  boolean firstCommand = (commandChainingBuffer[TEMP_INS] != buffer[ISO7816.OFFSET_INS]);
  // Mark the command chain as bad so it stays in this state in case of exception.
  short len = apdu.setIncomingAndReceive();
  if (len < 1) {
    ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
  }
  if (firstCommand) {
    Util.arrayCopyNonAtomic(buffer, (short) (ISO7816.OFFSET_CDATA + 1), commandChainingBuffer,
                            TEMP_GET_RESPONSE_DATA, (short) (len - 1));
    len = (short) (len - 1);
  } else {
    short existing = Util.getShort(commandChainingBuffer, TEMP_GET_RESPONSE_LENGTH);
    if ((short) (len + existing) > RSA_KEY_LENGTH_BYTES) {
      ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
    }
    Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, commandChainingBuffer,
                            (short) (TEMP_GET_RESPONSE_DATA + existing), len);
    len += existing;
  }
  if (len < RSA_KEY_LENGTH_BYTES) {
    commandChainingBuffer[TEMP_INS] = CMD_COMPUTE_PSO;
    Util.setShort(commandChainingBuffer, TEMP_GET_RESPONSE_LENGTH, len);
    return;  // For compatibily with GPG
  }
  // We have enough bytes to decrypt.
  cipherRSA.init(confidentialityKey.getPrivate(), Cipher.MODE_DECRYPT);
  len = cipherRSA.doFinal(commandChainingBuffer, TEMP_GET_RESPONSE_DATA, RSA_KEY_LENGTH_BYTES,
                          buffer, (short) 0);
  // Clear command chaining buffer to make ready for next operation.
  Util.arrayFillNonAtomic(commandChainingBuffer, (short) 0, (short) commandChainingBuffer.length, (byte) 0);
  apdu.setOutgoingAndSend((short) 0, len);
}
 
Example #17
Source File: Gpg.java    From OpenPGP-Card with GNU General Public License v3.0 4 votes vote down vote up
/**
 * Only this class's install method should create the applet object.
 */
protected Gpg(byte[] parameters, short offset, byte length) {
  pinLength = new byte[3];
  pins = new OwnerPIN[3];
  pins[PIN_INDEX_PW1] = new OwnerPIN(MAX_TRIES_PIN1, MAX_PIN_LENGTH);
  pins[PIN_INDEX_PW1].update(defaultPIN, (short) 0, MIN_PIN1_LENGTH);
  pinLength[PIN_INDEX_PW1] = MIN_PIN1_LENGTH;
  pins[PIN_INDEX_PW3] = new OwnerPIN(MAX_TRIES_PIN3, MAX_PIN_LENGTH);
  pins[PIN_INDEX_PW3].update(defaultPIN, (short) 0, MIN_PIN3_LENGTH);
  pinLength[PIN_INDEX_PW3] = MIN_PIN3_LENGTH;
  // The resetting code is disabled by default.
  pins[PIN_INDEX_RC] = new OwnerPIN(MAX_TRIES_RC, MAX_PIN_LENGTH);
  pinLength[PIN_INDEX_RC] = 0;
  pinSubmitted = JCSystem.makeTransientBooleanArray((short) 2, JCSystem.CLEAR_ON_DESELECT);

  commandChainingBuffer =
      JCSystem.makeTransientByteArray((short) (TEMP_PUT_KEY_ACCUMULATOR + RSA_KEY_LENGTH_BYTES),
                                      JCSystem.CLEAR_ON_DESELECT);

  privateDO1 = new byte[255];
  privateDO2 = new byte[255];
  privateDO3 = new byte[255];
  privateDO4 = new byte[255];

  loginData = new byte[(short) 255];
  url = new byte[(short) 255];
  name = new byte[(short) 40];
  language = new byte[(short) 9];
  sex = new byte[(short) 1];
  fingerprints = new byte[(short) 60];
  caFingerprints = new byte[(short) 60];
  generationDates = new byte[(short) 12];
  signatureCounter = new byte[(short) 3];
  pinValidForMultipleSignatures = (byte) 0;

  signatureKey = new KeyPair(KeyPair.ALG_RSA_CRT, (short) 2048);
  confidentialityKey = new KeyPair(KeyPair.ALG_RSA_CRT, (short) 2048);
  authenticationKey = new KeyPair(KeyPair.ALG_RSA_CRT, (short) 2048);
  cipherRSA = Cipher.getInstance(Cipher.ALG_RSA_PKCS1, false);
  randomData = RandomData.getInstance(RandomData.ALG_SECURE_RANDOM);

  register();
}
 
Example #18
Source File: Crypto.java    From ledger-javacard with GNU Affero General Public License v3.0 4 votes vote down vote up
public static void initCipherAES(AESKey key, boolean encrypt) {
    blobEncryptDecryptAES.init(key, (encrypt ? Cipher.MODE_ENCRYPT : Cipher.MODE_DECRYPT), IV_ZERO_AES, (short)0, (short)IV_ZERO_AES.length);
}
 
Example #19
Source File: Crypto.java    From ledger-javacard with GNU Affero General Public License v3.0 4 votes vote down vote up
public static void initCipher(DESKey key, boolean encrypt) {
    blobEncryptDecrypt.init(key, (encrypt ? Cipher.MODE_ENCRYPT : Cipher.MODE_DECRYPT), IV_ZERO, (short)0, (short)IV_ZERO.length);
}
 
Example #20
Source File: IsoApplet.java    From IsoApplet with GNU General Public License v3.0 4 votes vote down vote up
/**
 * \brief Compute a digital signature of the data from the apdu
 * 			using the private key referenced by	an earlier
 *			MANAGE SECURITY ENVIRONMENT apdu.
 *
 * \attention The apdu should contain a hash, not raw data for RSA keys.
 * 				PKCS1 padding will be applied if neccessary.
 *
 * \param apdu The PERFORM SECURITY OPERATION apdu with P1=9E and P2=9A.
 *
 * \throw ISOException SW_CONDITIONS_NOT_SATISFIED, SW_WRONG_LENGTH
 * 						and SW_UNKNOWN.
 */
private void computeDigitalSignature(APDU apdu) throws ISOException {
    byte[] buf = apdu.getBuffer();
    short offset_cdata;
    short lc;
    short sigLen = 0;


    switch(currentAlgorithmRef[0]) {
    case ALG_RSA_PAD_PKCS1:
        // Receive.
        // Bytes received must be Lc.
        lc = apdu.setIncomingAndReceive();
        if(lc != apdu.getIncomingLength()) {
            ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
        }
        offset_cdata = apdu.getOffsetCdata();

        // RSA signature operation.
        RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey) keys[currentPrivateKeyRef[0]];

        if(lc > (short) 247) {
            ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
        }

        rsaPkcs1Cipher.init(rsaKey, Cipher.MODE_ENCRYPT);
        sigLen = rsaPkcs1Cipher.doFinal(buf, offset_cdata, lc, ram_buf, (short)0);

        if(sigLen != 256) {
            ISOException.throwIt(ISO7816.SW_UNKNOWN);
        }

        // A single short APDU can handle 256 bytes - only one send operation neccessary.
        short le = apdu.setOutgoing();
        if(le < sigLen) {
            ISOException.throwIt(ISO7816.SW_CORRECT_LENGTH_00);
        }
        apdu.setOutgoingLength(sigLen);
        apdu.sendBytesLong(ram_buf, (short) 0, sigLen);
        break;

    case ALG_ECDSA_SHA1:
        // Get the key - it must be a EC private key,
        // checks have been done in MANAGE SECURITY ENVIRONMENT.
        ECPrivateKey ecKey = (ECPrivateKey) keys[currentPrivateKeyRef[0]];

        // Initialisation should be done when:
        // 	- No command chaining is performed at all.
        //	- Command chaining is performed and this is the first apdu in the chain.
        if(ram_chaining_cache[RAM_CHAINING_CACHE_OFFSET_CURRENT_POS] == (short) 0) {
            ecdsaSignature.init(ecKey, Signature.MODE_SIGN);
            if(isCommandChainingCLA(apdu)) {
                ram_chaining_cache[RAM_CHAINING_CACHE_OFFSET_CURRENT_POS] = (short) 1;
            }
        }

        short recvLen = apdu.setIncomingAndReceive();
        offset_cdata = apdu.getOffsetCdata();

        // Receive data. For extended APDUs, the data is received piecewise
        // and aggregated in the hash. When using short APDUs, command
        // chaining is performed.
        while (recvLen > 0) {
            ecdsaSignature.update(buf, offset_cdata, recvLen);
            recvLen = apdu.receiveBytes(offset_cdata);
        }

        if(!isCommandChainingCLA(apdu)) {
            sigLen = ecdsaSignature.sign(buf, (short)0, (short)0, buf, (short) 0);
            ram_chaining_cache[RAM_CHAINING_CACHE_OFFSET_CURRENT_POS] = (short) 0;
            apdu.setOutgoingAndSend((short) 0, sigLen);
        } else {
            ram_chaining_cache[RAM_CHAINING_CACHE_OFFSET_CURRENT_POS]++;
        }

        break;

    default:
        // Wrong/unknown algorithm.
        ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
    }
}
 
Example #21
Source File: PayPass.java    From CardExamples with The Unlicense 4 votes vote down vote up
public PayPass(byte[] bArray, short bOffset, byte bLength) {
    if (bLength != 27)
        ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
    // transaction starts
    JCSystem.beginTransaction();

    // set up and initialize all the DES encryption/descrytion ciphers used in the app
    DESKEY_KD_PERSO_L_EN = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES, KeyBuilder.LENGTH_DES, false);
    DESKEY_KD_PERSO_R_DE = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES, KeyBuilder.LENGTH_DES, false);
    DESKEY_KD_PERSO_L_DE = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES, KeyBuilder.LENGTH_DES, false);
    DESKEY_KD_PERSO_R_EN = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES, KeyBuilder.LENGTH_DES, false);
    CIPHER_KD_PERSO_L_EN = Cipher.getInstance(Cipher.ALG_DES_ECB_NOPAD, false);
    CIPHER_KD_PERSO_R_DE = Cipher.getInstance(Cipher.ALG_DES_ECB_NOPAD, false);
    CIPHER_KD_PERSO_L_DE = Cipher.getInstance(Cipher.ALG_DES_ECB_NOPAD, false);
    CIPHER_KD_PERSO_R_EN = Cipher.getInstance(Cipher.ALG_DES_ECB_NOPAD, false);

    // transaction ends
    JCSystem.commitTransaction();

    // define RAM buffers for faster operation
    CVC3_DATA = JCSystem.makeTransientByteArray((short) 16, JCSystem.CLEAR_ON_DESELECT);
    CMD_BUF = JCSystem.makeTransientByteArray((short) 261, JCSystem.CLEAR_ON_DESELECT);
    MAC = JCSystem.makeTransientByteArray((short) 8, JCSystem.CLEAR_ON_DESELECT);

    // on initialize the current state is not_alive
    state = not_alive;

    PROFILE = new Profile();

    // testing area
    // pre-personalization data
    // issuer supply
    PROFILE.VER_KMC = (byte) 0x01;  // MC version
    PROFILE.VER_KMC = bArray[bOffset];  // MC version
    PROFILE.KMC_ID[0] = (byte) 0x54;  // key id
    PROFILE.KMC_ID[1] = (byte) 0x13;
    PROFILE.KMC_ID[2] = (byte) 0x12;
    PROFILE.KMC_ID[3] = (byte) 0xFF;
    PROFILE.KMC_ID[4] = (byte) 0xFF;
    PROFILE.KMC_ID[5] = (byte) 0xFF;
    Util.arrayCopyNonAtomic(bArray, (short) (bOffset + 1), PROFILE.KMC_ID, (short) 0, (short) 6);
    PROFILE.KD_PERSO[0] = (byte) 0xA8;  // personalization key
    PROFILE.KD_PERSO[1] = (byte) 0x6A;
    PROFILE.KD_PERSO[2] = (byte) 0x3D;
    PROFILE.KD_PERSO[3] = (byte) 0x06;
    PROFILE.KD_PERSO[4] = (byte) 0xCA;
    PROFILE.KD_PERSO[5] = (byte) 0xE7;
    PROFILE.KD_PERSO[6] = (byte) 0x04;
    PROFILE.KD_PERSO[7] = (byte) 0x6A;
    PROFILE.KD_PERSO[8] = (byte) 0x10;
    PROFILE.KD_PERSO[9] = (byte) 0x63;
    PROFILE.KD_PERSO[10] = (byte) 0x58;
    PROFILE.KD_PERSO[11] = (byte) 0xD5;
    PROFILE.KD_PERSO[12] = (byte) 0xB8;
    PROFILE.KD_PERSO[13] = (byte) 0x23;
    PROFILE.KD_PERSO[14] = (byte) 0x9C;
    PROFILE.KD_PERSO[15] = (byte) 0xBE;
    Util.arrayCopyNonAtomic(bArray, (short) (bOffset + 7), PROFILE.KD_PERSO, (short) 0, (short) 16);
    PROFILE.CSN[0] = (byte) 0x89;
    PROFILE.CSN[1] = (byte) 0xAA;
    PROFILE.CSN[2] = (byte) 0x7F;
    PROFILE.CSN[3] = (byte) 0x00;
    Util.arrayCopyNonAtomic(bArray, (short) (bOffset + 23), PROFILE.CSN, (short) 0, (short) 4);
    // end issuer supply

    // profile can now be considered in personalization state
    PROFILE.STATE = PERSO;
}
 
Example #22
Source File: IsoApplet.java    From IsoApplet with GNU General Public License v3.0 4 votes vote down vote up
/**
 * \brief Decipher the data from the apdu using the private key referenced by
 * 			an earlier MANAGE SECURITY ENVIRONMENT apdu.
 *
 * \param apdu The PERFORM SECURITY OPERATION apdu with P1=80 and P2=86.
 *
 * \throw ISOException SW_CONDITIONS_NOT_SATISFIED, SW_WRONG_LENGTH and
 *						SW_WRONG_DATA
 */
private void decipher(APDU apdu) {
    short offset_cdata;
    short lc;
    short decLen = -1;

    lc = doChainingOrExtAPDU(apdu);
    offset_cdata = 0;

    // Padding indicator should be "No further indication".
    if(ram_buf[offset_cdata] != (byte) 0x00) {
        ISOException.throwIt(ISO7816.SW_WRONG_DATA);
    }

    switch(currentAlgorithmRef[0]) {

    case ALG_RSA_PAD_PKCS1:
        // Get the key - it must be an RSA private key,
        // checks have been done in MANAGE SECURITY ENVIRONMENT.
        RSAPrivateCrtKey theKey = (RSAPrivateCrtKey) keys[currentPrivateKeyRef[0]];

        // Check the length of the cipher.
        // Note: The first byte of the data field is the padding indicator
        //		 and therefor not part of the ciphertext.
        if((short)(lc-1) !=  (short)(theKey.getSize() / 8)) {
            ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
        }

        rsaPkcs1Cipher.init(theKey, Cipher.MODE_DECRYPT);
        try {
            decLen = rsaPkcs1Cipher.doFinal(ram_buf, (short)(offset_cdata+1), (short)(lc-1),
                                            apdu.getBuffer(), (short) 0);
        } catch(CryptoException e) {
            ISOException.throwIt(ISO7816.SW_WRONG_DATA);
        }

        // We have to send at most 256 bytes. A short APDU can handle that - only one send operation neccessary.
        apdu.setOutgoingAndSend((short)0, decLen);
        break;

    default:
        ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
    }
}
 
Example #23
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 #24
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 #25
Source File: GidsBaseTestClass.java    From GidsApplet with GNU General Public License v3.0 4 votes vote down vote up
protected void authenticateMutual(byte[] key, boolean successexpected) {
    byte[] myChallenge= new byte [16], globalchallenge = new byte[40], challengeresponse = new byte[40];
    byte[] cardChallenge;
    Cipher cipherDES = Cipher.getInstance(Cipher.ALG_DES_CBC_NOPAD, false);
    DESKey deskey = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES, KeyBuilder.LENGTH_DES3_3KEY, false);
    deskey.setKey(key, (short) 0);
    new Random().nextBytes(myChallenge);
    // select admin key
    execute("00 22 81 A4 03 83 01 80");
    // get a challenge
    ResponseAPDU response = execute("00 87 00 00 14 7C 12 81 10" + DatatypeConverter.printHexBinary(myChallenge) + "00");
    if (!Arrays.equals(Arrays.copyOfRange(response.getBytes(), 0, 4), new byte[] {0x7C,0x12,(byte) 0x81,0x10})) {
        fail("not a challenge:" + DatatypeConverter.printHexBinary(response.getBytes()));
    }
    // compute the response
    cardChallenge = Arrays.copyOfRange(response.getBytes(), 4, 20);
    //solve challenge
    //R2
    System.arraycopy(cardChallenge, 0, globalchallenge, 0, 16);
    //R1
    System.arraycopy(myChallenge, 0, globalchallenge, 16, 16);
    // keep Z1 random
    globalchallenge[(short)39] = (byte) 0x80;
    cipherDES.init(deskey, Cipher.MODE_ENCRYPT);
    cipherDES.doFinal(globalchallenge, (short) 0, (short)40, challengeresponse, (short) 0);
    // send the response
    String command = "00 87 00 00 2C 7C 2A 82 28" + DatatypeConverter.printHexBinary(challengeresponse);
    
    ResponseAPDU responseAPDU = execute(command, true);
    
    if (!successexpected)
    {
        if(responseAPDU.getSW() != 0x6982) {
            fail("expected: " + Integer.toHexString(0x6982) + " but was: " + Integer.toHexString(response.getSW()));
        }
        return;
    }
    if(responseAPDU.getSW() != 0x9000) {
        fail("expected: " + Integer.toHexString(0x9000) + " but was: " + Integer.toHexString(response.getSW()));
    }
    byte[] cardresponse = responseAPDU.getBytes();
    if (!Arrays.equals(Arrays.copyOfRange(cardresponse, 0, 4), new byte[] {0x7C,0x2A,(byte)0x82,0x28}))
    {
        fail("header verification failed");
    }
    byte[] decryptedCardResponse = new byte[40];
    cipherDES.init(deskey, Cipher.MODE_DECRYPT);
    cipherDES.doFinal(cardresponse, (short) 4, (short)40, decryptedCardResponse, (short) 0);
   
    
    if (!Arrays.equals(Arrays.copyOfRange(decryptedCardResponse, 0, 16), myChallenge)) {
        fail("R1 verification failed");
    }
    
    if (!Arrays.equals(Arrays.copyOfRange(decryptedCardResponse, 16, 32), cardChallenge)) {
        fail("R2 verification failed");
    }
    if (decryptedCardResponse[(short)39] != (byte) 0x80) {
        fail("padding failed");
    }
    
}
 
Example #26
Source File: GidsApplet.java    From GidsApplet with GNU General Public License v3.0 4 votes vote down vote up
/**
 * \brief Compute a digital signature of the data from the apdu
 * 			using the private key referenced by	an earlier
 *			MANAGE SECURITY ENVIRONMENT apdu.
 *
 * \attention The apdu should contain a hash, not raw data for RSA keys.
 * 				PKCS1 padding will be applied if neccessary.
 *
 * \param apdu The PERFORM SECURITY OPERATION apdu with P1=9E and P2=9A.
 *
 * \throw ISOException SW_CONDITIONS_NOT_SATISFIED, SW_WRONG_LENGTH
 * 						and SW_UNKNOWN.
 */
private void computeDigitalSignature(APDU apdu) throws ISOException {
    byte[] buf = apdu.getBuffer();
    short lc, le;
    short sigLen = 0;
    PrivateKey rsaKey = null;
    byte[] ram_buf = transmitManager.GetRamBuffer();
    CRTKeyFile key = (CRTKeyFile) currentKey[0];

    switch((byte) (currentAlgorithmRef[0] & 0xF0)) {
    case (byte) 0x10:
        // padding made off card -> raw encryption to be performed
        lc = transmitManager.doChainingOrExtAPDU(apdu);

        // RSA signature operation.
        rsaKey = key.GetKey().getPrivate();

        rsaRawCipher.init(rsaKey, Cipher.MODE_ENCRYPT);
        sigLen = rsaRawCipher.doFinal(ram_buf, (short) 0, lc, ram_buf, (short)0);

        transmitManager.sendDataFromRamBuffer(apdu, (short)0, sigLen);
        break;
    case (byte) 0x50:
        // rsa padding made by the card, only the hash is provided

        // Receive.
        // Bytes received must be Lc.
        lc = apdu.setIncomingAndReceive();

        // RSA signature operation.
        rsaKey = key.GetKey().getPrivate();

        if(lc > (short) 247) {
            ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
        }
        
        rsaPkcs1Cipher.init(rsaKey, Cipher.MODE_ENCRYPT);
        sigLen = rsaPkcs1Cipher.doFinal(buf, ISO7816.OFFSET_CDATA, lc, ram_buf, (short)0);

        /*if(sigLen != 256) {
            ISOException.throwIt(ISO7816.SW_UNKNOWN);
        }*/

        transmitManager.sendDataFromRamBuffer(apdu, (short)0, sigLen);
        break;

    default:
        // Wrong/unknown algorithm.
        ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
    }
}
 
Example #27
Source File: GidsApplet.java    From GidsApplet with GNU General Public License v3.0 4 votes vote down vote up
/**
 * \brief Decipher the data from the apdu using the private key referenced by
 * 			an earlier MANAGE SECURITY ENVIRONMENT apdu.
 *
 * \param apdu The PERFORM SECURITY OPERATION apdu with P1=80 and P2=86.
 *
 * \throw ISOException SW_CONDITIONS_NOT_SATISFIED, SW_WRONG_LENGTH and
 *						SW_WRONG_DATA
 */
private void decipher(APDU apdu) {
    byte[] buf = apdu.getBuffer();
    short offset_cdata;
    short lc;
    short decLen = -1;
    byte[] ram_buf = transmitManager.GetRamBuffer();
    Cipher cipher = null;

    lc = transmitManager.doChainingOrExtAPDU(apdu);
    offset_cdata = 0;

    // Padding indicator should be "No further indication".
    if(buf[offset_cdata] != (byte) 0x00) {
        ISOException.throwIt(ISO7816.SW_WRONG_DATA);
    }

    switch((byte) (currentAlgorithmRef[0] & 0xF0)) {

    case (byte) 0x80:
        cipher = rsaOaepCipher;
        break;
    case (byte) 0x40:
        cipher = rsaPkcs1Cipher;
        break;
    case (byte) 0x00:
        cipher = rsaRawCipher;
        break;
    default:
        ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
    }
    // Get the key - it must be an RSA private key,
    // checks have been done in MANAGE SECURITY ENVIRONMENT.
    CRTKeyFile key = (CRTKeyFile) currentKey[0];
    PrivateKey theKey = key.GetKey().getPrivate();

    // Check the length of the cipher.
    // Note: The first byte of the data field is the padding indicator
    //		 and therefor not part of the ciphertext.
    if(lc !=  (short)(theKey.getSize() / 8)) {
        ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
    }

    cipher.init(theKey, Cipher.MODE_DECRYPT);

    try {
        decLen = cipher.doFinal(ram_buf, (short) 0, lc,
                                buf, (short) 0);
    } catch(CryptoException e) {
        ISOException.throwIt(ISO7816.SW_WRONG_DATA);
    }

    // We have to send at most 256 bytes. A short APDU can handle that - only one send operation neccessary.
    apdu.setOutgoingAndSend((short)0, decLen);
}
 
Example #28
Source File: GidsApplet.java    From GidsApplet with GNU General Public License v3.0 4 votes vote down vote up
/**
 * \brief Only this class's install method should create the applet object.
 */
protected GidsApplet() {

    // by default the pin manager is in "initialization mode"
    pinManager = new GidsPINManager();

    transmitManager = new TransmitManager();

    currentAlgorithmRef = JCSystem.makeTransientByteArray((short)1, JCSystem.CLEAR_ON_DESELECT);
    currentKey = JCSystem.makeTransientObjectArray((short)1, JCSystem.CLEAR_ON_DESELECT);

    rsaPkcs1Cipher = Cipher.getInstance(Cipher.ALG_RSA_PKCS1, false);
    try {
        rsaOaepCipher = Cipher.getInstance(Cipher.ALG_RSA_PKCS1_OAEP, false);
    } catch (CryptoException e) {
        if(e.getReason() == CryptoException.NO_SUCH_ALGORITHM) {
            rsaOaepCipher = null;
        } else {
            throw e;
        }
    }
    rsaRawCipher = Cipher.getInstance(Cipher.ALG_RSA_NOPAD, false);

    byte mechanisms =  (byte) 0xC0;
    fs = new GidsFileSystem(pinManager, transmitManager, (short) 0x3F00,
                            // FCP
                            new byte[]	{
                                (byte)0x62, (byte)0x08,
                                (byte)0x82, (byte)0x01, (byte)0x38, // File descriptor byte.
                                (byte)0x8C, (byte)0x03, (byte)0x03, (byte)0x30, (byte)0x30,// security attribute
                            },
                            // FCI
                            new byte[]	{
                                0x61, 0X12,
                                0x4F, 0x0B, (byte) 0xA0, (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x97, (byte) 0x42, (byte) 0x54, (byte) 0x46, (byte) 0x59, 0x02, 0x01, // AID
                                0x73, 0x03,
                                0x40, 0x01, mechanisms, // cryptographic mechanism
                            },
                            // FMD
                            new byte[]	{
                                (byte)0x64, (byte)0x09,
                                (byte)0x5F, (byte)0x2F, (byte) 0x01, (byte) 0x60, // pin usage policy
                                (byte)0x7F, (byte)0x65, 0x02, (byte) 0x80, 0x00
                            }
                           );

    // FCI / FMD / FCP are hard coded
    register();
}
 
Example #29
Source File: SecureChannel.java    From status-keycard with Apache License 2.0 4 votes vote down vote up
/**
 * Sends the response to the command. This the given SW is appended to the data automatically. The response data must
 * be placed starting at the SecureChannel.SC_OUT_OFFSET offset, to leave place for the SecureChannel-specific data at
 * the beginning of the APDU.
 *
 * @param apdu the APDU object
 * @param len the length of the plaintext
 */
public void respond(APDU apdu, short len, short sw) {
  byte[] apduBuffer = apdu.getBuffer();

  Util.setShort(apduBuffer, (short) (SC_OUT_OFFSET + len), sw);
  len += 2;

  crypto.aesCbcIso9797m2.init(scEncKey, Cipher.MODE_ENCRYPT, secret, (short) 0, SC_BLOCK_SIZE);
  len = crypto.aesCbcIso9797m2.doFinal(apduBuffer, SC_OUT_OFFSET, len, apduBuffer, (short)(ISO7816.OFFSET_CDATA + SC_BLOCK_SIZE));

  apduBuffer[0] = (byte) (len + SC_BLOCK_SIZE);

  computeAESMAC(len, apduBuffer);

  Util.arrayCopyNonAtomic(apduBuffer, ISO7816.OFFSET_CDATA, secret, (short) 0, SC_BLOCK_SIZE);

  len += SC_BLOCK_SIZE;
  apdu.setOutgoingAndSend(ISO7816.OFFSET_CDATA, len);
}
 
Example #30
Source File: Bignat_Helper.java    From JCMathLib with MIT License 4 votes vote down vote up
void initialize(short modRSAEngineMaxBits, short multRSAEngineMaxBits) {
    MODULO_RSA_ENGINE_MAX_LENGTH_BITS = modRSAEngineMaxBits;
    MULT_RSA_ENGINE_MAX_LENGTH_BITS = multRSAEngineMaxBits;
    
    fnc_deep_resize_tmp = rm.helper_BN_array1;
    fnc_mult_resultArray1 = rm.helper_BN_array1;
    fnc_mult_resultArray2 = rm.helper_BN_array2;

    fnc_same_value_array1 = rm.helper_BN_array1;
    fnc_same_value_hash = rm.helper_BN_array2;
    
    fnc_shift_bytes_right_tmp = rm.helper_BN_array1;
    
    // BN below are just reassigned allocated helper_BN_? so that same helper_BN_? is not used in parallel (checked by lock() unlock())
    fnc_mod_add_tmp = rm.helper_BN_A;

    fnc_mod_sub_tmpThis = rm.helper_BN_A;
    fnc_mod_sub_tmp = rm.helper_BN_B;
    fnc_mod_sub_tmpOther = rm.helper_BN_C;

    fnc_mult_mod_tmpThis = rm.helper_BN_A;
    fnc_mult_mod_tmp_mod = rm.helper_BN_B;
    fnc_mult_mod_tmp_x = rm.helper_BN_C;

    fnc_exponentiation_tmp = rm.helper_BN_A;
    fnc_exponentiation_i = rm.helper_BN_B;

    fnc_mod_minus_2 = rm.helper_BN_B;

    fnc_negate_tmp = rm.helper_BN_B;

    fnc_sqrt_S = rm.helper_BN_A;
    fnc_sqrt_exp = rm.helper_BN_A;
    fnc_sqrt_p_1 = rm.helper_BN_B;
    fnc_sqrt_Q = rm.helper_BN_C;
    fnc_sqrt_tmp = rm.helper_BN_D;
    fnc_sqrt_z = rm.helper_BN_E;

    fnc_mod_mult_tmpThis = rm.helper_BN_E; // mod_mult is called from  fnc_sqrt => requires helper_BN_E not being locked in fnc_sqrt when mod_mult is called

    fnc_divide_tmpThis = rm.helper_BN_E; // divide is called from  fnc_sqrt => requires helper_BN_E not being locked  in fnc_sqrt when divide is called

    fnc_mod_exp_modBN = rm.helper_BN_F;  // mod_exp is called from  fnc_sqrt => requires helper_BN_F not being locked  in fnc_sqrt when mod_exp is called

    fnc_int_add_tmpMag = rm.helper_BN_A;
    fnc_int_multiply_mod = rm.helper_BN_A;
    fnc_int_multiply_tmpThis = rm.helper_BN_B;
    fnc_int_divide_tmpThis = rm.helper_BN_A;        
    
    
    // Allocate BN constants always in EEPROM (only reading)
    ONE = new Bignat((short) 1, JCSystem.MEMORY_TYPE_PERSISTENT, this);
    ONE.one();
    TWO = new Bignat((short) 1, JCSystem.MEMORY_TYPE_PERSISTENT, this);
    TWO.two();
    THREE = new Bignat((short) 1, JCSystem.MEMORY_TYPE_PERSISTENT, this);
    THREE.three();

    tmp_array_short = rm.memAlloc.allocateByteArray((short) 2, JCSystem.MEMORY_TYPE_TRANSIENT_RESET); // only 2b RAM for faster add(short)
    fnc_NmodE_cipher = Cipher.getInstance(Cipher.ALG_RSA_NOPAD, false);
    fnc_NmodE_pubKey = (RSAPublicKey) KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PUBLIC, MODULO_RSA_ENGINE_MAX_LENGTH_BITS, false);

    // Speedup for fast multiplication
    fnc_mult_keypair = new KeyPair(KeyPair.ALG_RSA_CRT, MULT_RSA_ENGINE_MAX_LENGTH_BITS);
    fnc_mult_keypair.genKeyPair();
    fnc_mult_pubkey_pow2 = (RSAPublicKey) fnc_mult_keypair.getPublic();
    //mult_privkey_pow2 = (RSAPrivateCrtKey) mult_keypair.getPrivate();
    fnc_mult_pubkey_pow2.setExponent(CONST_TWO, (short) 0, (short) CONST_TWO.length);
    fnc_mult_cipher = Cipher.getInstance(Cipher.ALG_RSA_NOPAD, false);

    hashEngine = rm.hashEngine;

    FLAG_FAST_MULT_VIA_RSA = false; // set true only if succesfully allocated and tested below
    try { // Subsequent code may fail on some real (e.g., Infineon CJTOP80K) cards - catch exception
        fnc_mult_cipher.init(fnc_mult_pubkey_pow2, Cipher.MODE_ENCRYPT);
        // Try operation - if doesn't work, exception SW_CANTALLOCATE_BIGNAT is emitted
        Util.arrayFillNonAtomic(fnc_mult_resultArray1, (short) 0, (short) fnc_mult_resultArray1.length, (byte) 6);
        fnc_mult_cipher.doFinal(fnc_mult_resultArray1, (short) 0, (short) fnc_mult_resultArray1.length, fnc_mult_resultArray1, (short) 0);
        FLAG_FAST_MULT_VIA_RSA = true;
    } catch (Exception ignored) {
    } // discard exception                
}