package sega.a7; import javacard.framework.Util; import javacard.security.MessageDigest; public class AuthCommand extends Command { private Crypt m_ee_crypt; private HmacSha1 m_ee_hmacSha1; private byte m_ee_authLevel = 0; public AuthCommand(short cmd, short recvPacketSize, short sendPacketSize, byte authLevel, AppData data, MakePacket packet, MessageDigest sha1, HmacSha1 hmacSha1, Crypt crypt) { super(cmd, recvPacketSize, sendPacketSize, data, packet, sha1); this.m_ee_crypt = crypt; this.m_ee_hmacSha1 = hmacSha1; this.m_ee_authLevel = authLevel; this.m_ee_tag = AppConfig.A7_TAG_RQU_AUTH_COMMAND; } public short execute(byte[] data, short dataOffest, short dataLength, byte[] dst, short dstOffset, short dstLength) { if (this.m_ee_data.getSession_ramD() != 1) return makeErrorPacket(AppConfig.A7_INVALID_AUTH, dst, dstOffset, dstLength); if (this.m_ee_authLevel != this.m_ee_data.getLevel_ramD()) return makeErrorPacket(AppConfig.A7_LV_ERROR, dst, (short) dstOffset, (short) dstLength); short ramD_error = checkHeader(data, dataOffest, dataLength); if (ramD_error != AppConfig.A7_SUCCESS) return makeErrorPacket(ramD_error, dst, dstOffset, dstLength); ramD_error = checkFooter(data, dataOffest, dataLength); if (ramD_error != AppConfig.A7_SUCCESS) return makeErrorPacket(ramD_error, dst, dstOffset, dstLength); this.m_ramD_outDataInfo[0] = 0; this.m_ramD_outDataInfo[1] = 0; ramD_error = core(data, dataOffest, dataLength); if (ramD_error != AppConfig.A7_SUCCESS) return makeErrorPacket(ramD_error, dst, dstOffset, dstLength); return makeSendAuthPacket(AppConfig.A7_TAG_RSP_AUTH_COMMAND, this.m_ramD_setSendPacketSize[0], (short) 0, this.m_ramD_outData, this.m_ramD_outDataInfo[0], this.m_ramD_outDataInfo[1], data, (short) (dataLength - AppConfig.FOOTER_SIZE + dataOffest), (short) 20, dst, dstOffset, dstLength); } protected boolean changeConnectionKey_ee(byte[] aesKey, short aesKeyOffset, short aesKeyLength, byte[] aesIv, short aesIvOffset, short aesIvLength) { byte[] ramD_tmp = this.m_ee_data.getCryptBuffer_ramD(); Util.arrayFillNonAtomic(ramD_tmp, (short) 0, (short) ramD_tmp.length, (byte) 0); if (!this.m_ee_crypt.init(aesKey, aesKeyOffset, aesKeyLength, ramD_tmp, (short) 0, (short) ramD_tmp.length, Crypt.AES_MODE_CKEY_ENCRYPT)) return false; if (!this.m_ee_crypt.init(aesKey, aesKeyOffset, aesKeyLength, ramD_tmp, (short) 0, (short) ramD_tmp.length, Crypt.AES_MODE_CKEY_DECRYPT)) return false; this.m_ee_data.setCkeyIv_ramD(aesIv, aesIvOffset, aesIvLength); return true; } protected boolean changeGKey_ee(byte[] aesKey, short aesKeyOffset, short aesKeyLength, byte[] aesIv, short aesIvOffset, short aesIvLength) { byte[] ramD_tmp = this.m_ee_data.getCryptBuffer_ramD(); Util.arrayFillNonAtomic(ramD_tmp, (short) 0, (short) ramD_tmp.length, (byte) 0); if (!this.m_ee_crypt.init(aesKey, aesKeyOffset, aesKeyLength, ramD_tmp, (short) 0, (short) ramD_tmp.length, Crypt.AES_MODE_GKEY_ENCRYPT)) return false; if (!this.m_ee_crypt.init(aesKey, aesKeyOffset, aesKeyLength, ramD_tmp, (short) 0, (short) ramD_tmp.length, Crypt.AES_MODE_GKEY_DECRYPT)) return false; this.m_ee_data.setGkeyIv_ee(aesIv, aesIvOffset, aesIvLength); return true; } protected short decData(byte[] src, short srcOffset, short srcLength, byte[] dst, short dstOffset) { byte[] ramD_iv = this.m_ee_data.getCkeyIv_ramD(); short size = this.m_ee_crypt.doFinal(src, srcOffset, srcLength, dst, dstOffset, Crypt.AES_MODE_CKEY_DECRYPT); for (short ramD_ii = 0; ramD_ii < ramD_iv.length; ramD_ii++) { short offset = (short) (ramD_ii + dstOffset); dst[offset] = (byte) (dst[offset] ^ ramD_iv[ramD_ii]); } return size; } protected short decUpdate_Gkey(byte[] src, short srcOffset, short srcLength, byte[] dst, short dstOffset, boolean bInit) { if (bInit) { byte[] tmp = this.m_ee_data.getCryptBuffer_ramD(); this.m_ee_crypt.doFinal(tmp, (short) 0, AppConfig.AES_DATA_SIZE, tmp, (short) 0, Crypt.AES_MODE_GKEY_DECRYPT); } short size = this.m_ee_crypt.update(src, srcOffset, srcLength, dst, dstOffset, Crypt.AES_MODE_GKEY_DECRYPT); if (bInit) { byte[] ee_iv = this.m_ee_data.getGkeyIv_ee(); for (short ramD_ii = 0; ramD_ii < ee_iv.length; ramD_ii++) { short offset = (short) (ramD_ii + dstOffset); dst[offset] = (byte) (dst[offset] ^ ee_iv[ramD_ii]); } } return size; } protected short encData(byte[] src, short srcOffset, short srcLength, byte[] dst, short dstOffset) { byte[] ramD_tmp = this.m_ee_data.getCryptBuffer_ramD(); byte[] ramD_iv = this.m_ee_data.getCkeyIv_ramD(); short ramD_ii = (short) 0; for (ramD_ii = 0; ramD_ii < 16; ramD_ii++) { if (ramD_ii < srcLength) { ramD_tmp[ramD_ii] = (byte) (src[ramD_ii + srcOffset] ^ ramD_iv[ramD_ii]); } else { ramD_tmp[ramD_ii] = (byte) (0x0 ^ ramD_iv[ramD_ii]); } ramD_tmp[ramD_ii] = (byte) (0x0 ^ ramD_tmp[ramD_ii]); } if (srcLength > 16) { short size = 0; size += this.m_ee_crypt.update(ramD_tmp, (short) 0, (short) ramD_tmp.length, dst, dstOffset, (short) 2); size += this.m_ee_crypt.doFinal(src, (short) (srcOffset + 16), (short) (srcLength - 16), dst, (short) (dstOffset + 16), (short) 2); return size; } return this.m_ee_crypt.doFinal(ramD_tmp, (short) 0, (short) ramD_tmp.length, dst, dstOffset, Crypt.AES_MODE_CKEY_ENCRYPT); } protected short encUpdate_GKey(byte[] src, short srcOffset, short srcLength, byte[] dst, short dstOffset, boolean bInit) { if (!bInit) return this.m_ee_crypt.update(src, srcOffset, srcLength, dst, dstOffset, Crypt.AES_MODE_GKEY_ENCRYPT); byte[] ramD_tmp = this.m_ee_data.getCryptBuffer_ramD(); byte[] ee_iv = this.m_ee_data.getGkeyIv_ee(); this.m_ee_crypt.doFinal(ramD_tmp, (short) 0, AppConfig.AES_DATA_SIZE, ramD_tmp, (short) 0, Crypt.AES_MODE_GKEY_ENCRYPT); for (short ramD_ii = 0; ramD_ii < AppConfig.AES_DATA_SIZE; ramD_ii++) { if (ramD_ii < srcLength) { ramD_tmp[ramD_ii] = (byte) (src[ramD_ii + srcOffset] ^ ee_iv[ramD_ii]); } else { ramD_tmp[ramD_ii] = (byte) (short) (0x0 ^ ee_iv[ramD_ii]); } ramD_tmp[ramD_ii] = (byte) (short) (0x0 ^ ramD_tmp[ramD_ii]); } if (srcLength > AppConfig.AES_DATA_SIZE) { short size = 0; size += this.m_ee_crypt.update(ramD_tmp, (short) 0, (short) ramD_tmp.length, dst, dstOffset, Crypt.AES_MODE_GKEY_ENCRYPT); size += this.m_ee_crypt.update(src, (short) (srcOffset + AppConfig.AES_DATA_SIZE), (short) (srcLength - AppConfig.AES_DATA_SIZE), dst, (short) (dstOffset + AppConfig.AES_DATA_SIZE), Crypt.AES_MODE_GKEY_ENCRYPT); return size; } return this.m_ee_crypt.update(ramD_tmp, (short) 0, (short) ramD_tmp.length, dst, dstOffset, Crypt.AES_MODE_GKEY_ENCRYPT); } protected boolean changeRsaKey_ee(byte[] data1, short data1Offset, short data1Length, byte[] data2, short data2Offset, short data2Length) { return this.m_ee_crypt.init(data1, data1Offset, data1Length, data2, data2Offset, data2Length, Crypt.RSA_MODE_DECRYPT); } protected short rsaDecData(byte[] src, short srcOffset, short srcLength, byte[] dst, short dstOffset) { return this.m_ee_crypt.doFinal(src, srcOffset, srcLength, dst, dstOffset, Crypt.RSA_MODE_DECRYPT); } /** * Validate authenticated packet footer. * The footer is 40 bytes. * 20 bytes: nonce * 20 bytes: MAC(SHA1(packet[:footer]) | nonce) == signature */ protected short checkFooter(byte[] data, short dataOffset, short dataLength) { short ramD_oddOffset = (short) (dataOffset + dataLength - AppConfig.FOOTER_SIZE); short ramD_authOfset = (short) (dataOffset + dataLength - AppConfig.A7_AUTH_SIZE); byte[] ramD_buffer = this.m_ee_data.getFooterBuffer_ramD(); byte[] ramD_kh = this.m_ee_data.getKh_ramD(); byte[] ramD_lastNonce = this.m_ee_data.getLastNonceEvent_ramD(); this.m_ee_sha1.reset(); this.m_ee_sha1.doFinal(data, dataOffset, (short) (dataLength - AppConfig.FOOTER_SIZE), ramD_buffer, (short) 0); this.m_ee_hmacSha1.init(ramD_kh, (short) 0, (short) ramD_kh.length); this.m_ee_hmacSha1.update(ramD_buffer, (short) 0, (short) 20); this.m_ee_hmacSha1.update(ramD_lastNonce, (short) 0, (short) ramD_lastNonce.length); this.m_ee_hmacSha1.sign(data, ramD_oddOffset, (short) 20, ramD_buffer, (short) 0); if (Util.arrayCompare(data, ramD_authOfset, ramD_buffer, (short) 0, (short) 20) != 0) { this.m_ee_data.incrementErrorCount(); return AppConfig.A7_AUTHFAIL; } this.m_ee_data.clearErrorCount(); return AppConfig.A7_SUCCESS; } protected short makeSendAuthPacket(short tag, short paramSize, short result, byte[] data, short dataOffset, short dataSize, byte[] nonceOdd, short oddOffset, short oddLength, byte[] sendPacket, short packetOffset, short packetLength) { byte[] ramD_nonceEvent = this.m_ee_data.getNewNonceEvent_ramD(); if (!this.m_ee_packet.setData(this.m_ee_data.getKh_ramD(), (short) 0, (short) this.m_ee_data.getKh_ramD().length, tag, paramSize, result, this.m_ee_cmd, data, dataOffset, dataSize, ramD_nonceEvent, (short) 0, (short) ramD_nonceEvent.length, nonceOdd, oddOffset, oddLength, sendPacket, packetOffset, packetLength, this.m_ee_sha1, this.m_ee_hmacSha1)) return makeErrorPacket(AppConfig.A7_FAIL, sendPacket, packetOffset, packetLength); this.m_ee_data.setLastNonceEvent_ramD(ramD_nonceEvent, (short) 0, (short) ramD_nonceEvent.length); return paramSize; } }