/** Process the INTERNAL AUTHENTICATE instruction (0x88) ISO 7816-4 Section 7.5.2 */ private void processInternalAuthenticate(APDU apdu) { if (state != STATE_PERSONALISED) { ISOException.throwIt(SW_INS_NOT_SUPPORTED); } if (!pin.isValidated()) { ISOException.throwIt(SW_SECURITY_STATUS_NOT_SATISFIED); } byte[] buf = apdu.getBuffer(); short lc = unsigned(buf[OFFSET_LC]); if (lc == 0) { ISOException.throwIt(SW_WRONG_LENGTH); } apdu.setIncomingAndReceive(); RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey) currentPrivateKey[0]; byte alg = tmp[TMP_SIGNALG_OFFSET]; if (privateKey != authKeyPrivate || alg != ALG_AUTH_DEC_RSA) { ISOException.throwIt(SW_WRONG_DATA); } short offset = OFFSET_CDATA; short maxLength = (short) ((short) (privateKey.getSize() / 8) - 11); if (lc > maxLength) { ISOException.throwIt(SW_WRONG_LENGTH); } pkcs1Cipher.init(privateKey, Cipher.MODE_ENCRYPT); short len = pkcs1Cipher.doFinal(buf, offset, lc, tmp, TMP_OFFSET); Util.arrayCopyNonAtomic(tmp, TMP_OFFSET, buf, (short) 0, len); apdu.setOutgoingAndSend((short) 0, len); }
/** Process the PSO COMPUTE DIGITAL SIGNATURE instruction (0x2A) ISO 7816-8 Section 5.4 */ private void processComputeDigitalSignature(APDU apdu) { pin.reset(); byte[] buf = apdu.getBuffer(); short lc = unsigned(buf[OFFSET_LC]); if (lc == 0) { ISOException.throwIt(SW_WRONG_LENGTH); } apdu.setIncomingAndReceive(); RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey) currentPrivateKey[0]; byte alg = tmp[TMP_SIGNALG_OFFSET]; if (privateKey != signKeyPrivate || (alg != ALG_SIGN_RSA_PKCS1_SHA1 && alg != ALG_SIGN_RSA_PKCS1_SHA256 && alg != ALG_SIGN_RSA_PSS && alg != ALG_SIGN_RSA_PKCS1_SHA1MD5)) { ISOException.throwIt(SW_WRONG_DATA); } short offset = OFFSET_CDATA; short expectedLength = 0; if (alg == ALG_SIGN_RSA_PKCS1_SHA256) { expectedLength = (short) (SHA256_LEN + 17); } else if (alg == ALG_SIGN_RSA_PKCS1_SHA1) { expectedLength = (short) (SHA1_LEN + 13); } else if (alg == ALG_SIGN_RSA_PSS) { expectedLength = SHA1_LEN; } else if (alg == ALG_SIGN_RSA_PKCS1_SHA1MD5) { expectedLength = SHA1MD5_LEN; } if (lc != expectedLength) { ISOException.throwIt(SW_WRONG_LENGTH); } short sigLen = 0; if (alg == ALG_SIGN_RSA_PKCS1_SHA1 || alg == ALG_SIGN_RSA_PKCS1_SHA256 || alg == ALG_SIGN_RSA_PKCS1_SHA1MD5) { pkcs1Cipher.init(privateKey, Cipher.MODE_ENCRYPT); sigLen = pkcs1Cipher.doFinal(buf, offset, lc, tmp, TMP_OFFSET); Util.arrayCopyNonAtomic(tmp, TMP_OFFSET, buf, (short) 0, sigLen); } else { short emLen = (short) (privateKey.getSize() / 8); pssPad(buf, offset, lc, tmp, TMP_OFFSET, emLen, signKeyFirstModulusByte); nopadCipher.init(privateKey, Cipher.MODE_ENCRYPT); sigLen = nopadCipher.doFinal(tmp, (short) 0, emLen, buf, (short) 0); } apdu.setOutgoingAndSend((short) 0, sigLen); }
private void processSetupKey(APDU apdu) throws ISOException { if (state != STATE_INITIAL) { ISOException.throwIt(SW_CONDITIONS_NOT_SATISFIED); } byte[] buf = apdu.getBuffer(); byte p1 = buf[OFFSET_P1]; byte p2 = buf[OFFSET_P2]; short lc = unsigned(buf[OFFSET_LC]); apdu.setIncomingAndReceive(); if (p1 == (byte) 0x61 || p1 == (byte) 0x62 || p1 == (byte) 0x63) { if (lc > 16) { ISOException.throwIt(SW_WRONG_LENGTH); } byte[] keyId = null; if (p1 == (byte) 0x61) { keyId = authKeyId; } else if (p1 == (byte) 0x62) { keyId = signKeyId; } else if (p1 == (byte) 0x63) { keyId = decKeyId; } Util.arrayCopy(buf, OFFSET_CDATA, keyId, (short) 1, lc); keyId[0] = (byte) lc; return; } RSAPrivateCrtKey privKey = null; if (p1 == (byte) 0x64) { privKey = authKeyPrivate; } else if (p1 == (byte) 0x65) { privKey = signKeyPrivate; } else if (p1 == (byte) 0x66) { privKey = decKeyPrivate; } else { ISOException.throwIt(SW_INCORRECT_P1P2); } try { switch (p2) { case (byte) 0x81: // Modulus, ignore, but record the first byte if key is sign key if (privKey == signKeyPrivate) { signKeyFirstModulusByte = buf[OFFSET_CDATA]; } break; case (byte) 0x82: // Exponent, ignore break; case (byte) 0x83: privKey.setP(buf, OFFSET_CDATA, lc); break; case (byte) 0x84: privKey.setQ(buf, OFFSET_CDATA, lc); break; case (byte) 0x85: privKey.setDP1(buf, OFFSET_CDATA, lc); break; case (byte) 0x86: privKey.setDQ1(buf, OFFSET_CDATA, lc); break; case (byte) 0x87: privKey.setPQ(buf, OFFSET_CDATA, lc); break; default: } } catch (Exception e) { ISOException.throwIt(SW_WRONG_DATA); } }
/** Process the PSO DECIPHER instruction. ISO 7816-8 Section 5.10 */ private void processDecipher(APDU apdu) { byte[] buf = apdu.getBuffer(); byte cla = buf[OFFSET_CLA]; boolean chain = ((byte) (cla & CLA_CHAIN) == CLA_CHAIN); short lc = unsigned(buf[OFFSET_LC]); // We need at least 1 byte of data to feed into the cipher, // so that a progression is made if (lc == 0) { ISOException.throwIt(SW_WRONG_LENGTH); } apdu.setIncomingAndReceive(); short offset = OFFSET_CDATA; // The first in chain, intialized and check: if (tmp[TMP_DECSEQ_OFFSET] == (byte) 0x00) { RSAPrivateCrtKey key = (RSAPrivateCrtKey) currentPrivateKey[0]; if (key == null) { ISOException.throwIt(SW_KEY_NOT_FOUND); } byte alg = tmp[TMP_SIGNALG_OFFSET]; if (key != decKeyPrivate || alg != ALG_AUTH_DEC_RSA) { ISOException.throwIt(SW_WRONG_DATA); } pkcs1Cipher.init(key, Cipher.MODE_DECRYPT); tmp[TMP_DECSEQ_OFFSET]++; expectedDecipherDataLength[0] = (short) (key.getSize() / 8); } short decipheredLen = 0; try { decipheredLen = pkcs1Cipher.update(buf, offset, lc, tmp, (short) (TMP_OFFSET + decipheredLen)); } catch (CryptoException ce) { ISOException.throwIt(SW_WRONG_DATA); } expectedDecipherDataLength[0] -= lc; offset += lc; // Data still to come: if (expectedDecipherDataLength[0] != 0 && !chain) { ISOException.throwIt(SW_WRONG_DATA); } // No more data: if (expectedDecipherDataLength[0] == 0 && chain) { ISOException.throwIt(SW_LAST_COMMAND_EXPECTED); } if (chain) { // It should also be the case the deciphereLen == 0, check? return; } pin.reset(); tmp[TMP_DECSEQ_OFFSET] = 0x00; try { decipheredLen = pkcs1Cipher.doFinal(buf, offset, (short) 0, tmp, (short) (TMP_OFFSET + decipheredLen)); } catch (CryptoException ce) { ISOException.throwIt(SW_WRONG_DATA); } Util.arrayCopyNonAtomic(tmp, TMP_OFFSET, buf, (short) 0, decipheredLen); apdu.setOutgoingAndSend((short) 0, decipheredLen); }