private PKIApplet() { pin = new OwnerPIN(PIN_TRIES, MAX_PIN_SIZE); puc = new OwnerPIN(PUC_TRIES, PUC_SIZE); rd = RandomData.getInstance(RandomData.ALG_SECURE_RANDOM); pkcs1Cipher = Cipher.getInstance(Cipher.ALG_RSA_PKCS1, false); nopadCipher = Cipher.getInstance(Cipher.ALG_RSA_NOPAD, false); md = MessageDigest.getInstance(MessageDigest.ALG_SHA, false); tmp = JCSystem.makeTransientByteArray(TMP_SIZE, JCSystem.CLEAR_ON_DESELECT); state = STATE_INITIAL; authKeyId = new byte[KEY_ID_SIZE]; signKeyId = new byte[KEY_ID_SIZE]; decKeyId = new byte[KEY_ID_SIZE]; authKeyPrivate = (RSAPrivateCrtKey) KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_CRT_PRIVATE, KeyBuilder.LENGTH_RSA_1024, false); signKeyPrivate = (RSAPrivateCrtKey) KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_CRT_PRIVATE, KeyBuilder.LENGTH_RSA_1024, false); decKeyPrivate = (RSAPrivateCrtKey) KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_CRT_PRIVATE, KeyBuilder.LENGTH_RSA_1024, false); tempKeyPublic = (RSAPublicKey) KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PUBLIC, KeyBuilder.LENGTH_RSA_1024, false); currentPrivateKey = JCSystem.makeTransientObjectArray((short) 1, JCSystem.CLEAR_ON_DESELECT); expectedDecipherDataLength = JCSystem.makeTransientShortArray((short) 1, JCSystem.CLEAR_ON_DESELECT); fileSystem = new FileSystem((short) 16); }
/** Process the GET CHALLENGE instruction (0x84) ISO 7816-4, Section 7.5.3 */ private void processGetChallenge(APDU apdu) { if (state != STATE_PERSONALISED) { ISOException.throwIt(SW_INS_NOT_SUPPORTED); } byte[] buf = apdu.getBuffer(); if (buf[OFFSET_P1] != 0x00 || buf[OFFSET_P2] != 0x00) { ISOException.throwIt(SW_INCORRECT_P1P2); } short le = apdu.setOutgoing(); if (le == 0) { ISOException.throwIt(SW_WRONG_LENGTH); } apdu.setOutgoingLength(le); rd.generateData(buf, (short) 0, le); apdu.sendBytes((short) 0, le); }
/** * Pads the input according to the RSASSA-PSS algorithm, the result is placed in output. The input * should be 20-byte SHA1 hash of the message to be signed. This method *does not* do signing * (encrypting) itself. Due to the randomness of this algorithm the subsequent signing may fail * (when the result of this method is larger than the key modulus) in which case the padding * should be attempted again. */ private void pssPad( byte[] input, short inOffset, short hashLen, byte[] output, short outputOffset, short emLen, byte firstKeyByte) throws CryptoException { do { short hLen = hashLen; short outOffset = outputOffset; if (hLen != SHA1_LEN || (short) (inOffset + hLen) > input.length || (short) (outOffset + emLen) > output.length) { CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } short sLen = SHA1_LEN; short psLen = (short) (emLen - sLen - hLen - 2); Util.arrayFillNonAtomic(output, outOffset, emLen, (byte) 0x00); md.update(output, outOffset, (short) 8); md.update(input, inOffset, hLen); rd.generateData(output, (short) (outOffset + psLen + 1), sLen); md.doFinal(output, (short) (outOffset + psLen + 1), sLen, tmp, TMP_HASH_OFFSET); output[(short) (outOffset + psLen)] = (byte) 0x01; Util.arrayFillNonAtomic(output, outOffset, psLen, (byte) 0x00); short hOffset = (short) (outOffset + emLen - hLen - 1); Util.arrayCopyNonAtomic(tmp, TMP_HASH_OFFSET, output, hOffset, hLen); output[(short) (outOffset + emLen - 1)] = (byte) 0xbc; tmp[(short) (TMP_C_OFFSET + C_LEN - 1)] = 0; while (outOffset < hOffset) { md.update(output, hOffset, hLen); md.doFinal(tmp, TMP_C_OFFSET, C_LEN, tmp, TMP_HASH_OFFSET); if ((short) (outOffset + hLen) > hOffset) { hLen = (short) (hOffset - outOffset); } for (short i = 0; i < hLen; i++) { output[outOffset++] ^= tmp[(short) (TMP_HASH_OFFSET + i)]; } tmp[(short) (TMP_C_OFFSET + C_LEN - 1)]++; } } while (firstKeyByte <= tmp[TMP_OFFSET]); }