diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c3af857 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +lib/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..e94cb97 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +> _"A wise man never leaves debugging symbols in production firmware"_ +> +> Sun Tzu, Art of War + +# What? +If you have to ask, this repo isn't useful for you. diff --git a/src/sega/a7/A7Firm.java b/src/sega/a7/A7Firm.java new file mode 100644 index 0000000..28ef929 --- /dev/null +++ b/src/sega/a7/A7Firm.java @@ -0,0 +1,164 @@ +package sega.a7; + +import javacard.framework.APDU; +import javacard.framework.Applet; +import javacard.framework.Util; +import javacard.security.MessageDigest; +import javacard.security.RandomData; +import javacardx.apdu.ExtendedLength; + +public class A7Firm extends Applet implements ExtendedLength { + private CommandServer m_ee_server = new CommandServer(); + MessageDigest m_ee_sha1 = MessageDigest.getInstance((byte) 1, false); + HmacSha1 m_ee_hmacSha1 = new HmacSha1(); + RandomData m_ee_random = RandomData.getInstance((byte) 2); + private AppData m_ee_data = new AppData(this.m_ee_random); + + private MakePacket m_ee_makePacket = new MakePacket(); + private Crypt m_ee_crypt = new Crypt(); + private AppBuffer m_ee_buffer = new AppBuffer(); + + public boolean select() { + if (!super.select()) + return false; + this.m_ee_buffer.clear_ramD(); + this.m_ee_data.init(); + this.m_ee_server.select(); + return true; + } + + public A7Firm() { + byte[] modulus = this.m_ee_data.getRsaDefaultPriModulus_ee(); + byte[] exponent = this.m_ee_data.getRsaDefaultPriExponent_ee(); + byte[] tmp = this.m_ee_data.getCryptBuffer_ramD(); + Util.arrayFillNonAtomic(tmp, (short) 0, (short) tmp.length, (byte) -1); + + // Zero all the keys + this.m_ee_crypt.init(tmp, (short) 0, (short) tmp.length, tmp, (short) 0, (short) tmp.length, + Crypt.AES_MODE_CKEY_DECRYPT); + this.m_ee_crypt.init(tmp, (short) 0, (short) tmp.length, tmp, (short) 0, (short) tmp.length, + Crypt.AES_MODE_CKEY_ENCRYPT); + this.m_ee_crypt.init(tmp, (short) 0, (short) tmp.length, tmp, (short) 0, (short) tmp.length, + Crypt.AES_MODE_GKEY_DECRYPT); + this.m_ee_crypt.init(tmp, (short) 0, (short) tmp.length, tmp, (short) 0, (short) tmp.length, + Crypt.AES_MODE_GKEY_ENCRYPT); + this.m_ee_crypt.init(modulus, (short) 0, (short) modulus.length, exponent, (short) 0, (short) exponent.length, + Crypt.RSA_MODE_DECRYPT); + + this.m_ee_server.setNoCommand(new NoCommand((short) -1, this.m_ee_data, this.m_ee_makePacket, this.m_ee_sha1)); + this.m_ee_server.attachCommand( + new SessionOpen(AppConfig.A7_ORD_SESSION_OPEN, this.m_ee_data, this.m_ee_makePacket, this.m_ee_sha1)); + this.m_ee_server.attachCommand( + new SessionClose(AppConfig.A7_ORD_SESSION_CLOSE, this.m_ee_data, this.m_ee_makePacket, this.m_ee_sha1)); + this.m_ee_server.attachCommand(new AuthStart(AppConfig.A7_ORD_AUTH_START, this.m_ee_data, this.m_ee_makePacket, + this.m_ee_sha1, this.m_ee_hmacSha1, this.m_ee_crypt)); + this.m_ee_server.attachCommand(new HmacChange(AppConfig.A7_ORD_HMAC_CHANGE, this.m_ee_data, + this.m_ee_makePacket, this.m_ee_sha1, this.m_ee_hmacSha1, this.m_ee_crypt)); + this.m_ee_server.attachCommand(new KeyChange(AppConfig.A7_ORD_KEY_CHANGE, this.m_ee_data, this.m_ee_makePacket, + this.m_ee_sha1, this.m_ee_hmacSha1, this.m_ee_crypt)); + this.m_ee_server.attachCommand( + new LvGet(AppConfig.A7_ORD_LV_GET, this.m_ee_data, this.m_ee_makePacket, this.m_ee_sha1)); + this.m_ee_server.attachCommand(new KeychipInfoWrite(AppConfig.A7_ORD_KEYCHIP_INFO_WRITE, this.m_ee_data, + this.m_ee_makePacket, this.m_ee_sha1, this.m_ee_hmacSha1, this.m_ee_crypt)); + this.m_ee_server.attachCommand(new KeychipInfoRead(AppConfig.A7_ORD_KEYCHIP_INFO_READ, this.m_ee_data, + this.m_ee_makePacket, this.m_ee_sha1, this.m_ee_hmacSha1, this.m_ee_crypt)); + this.m_ee_server.attachCommand(new GkeyWrite(AppConfig.A7_ORD_GKEY_WRITE, this.m_ee_data, this.m_ee_makePacket, + this.m_ee_sha1, this.m_ee_hmacSha1, this.m_ee_crypt)); + this.m_ee_server.attachCommand(new GkeyEnc(AppConfig.A7_ORD_GKEY_ENC, this.m_ee_data, this.m_ee_makePacket, + this.m_ee_sha1, this.m_ee_hmacSha1, this.m_ee_crypt)); + this.m_ee_server.attachCommand(new GkeyDec(AppConfig.A7_ORD_GKEY_DEC, this.m_ee_data, this.m_ee_makePacket, + this.m_ee_sha1, this.m_ee_hmacSha1, this.m_ee_crypt)); + this.m_ee_server.attachCommand(new SflagWrite(AppConfig.A7_ORD_SFLAG_WRITE, this.m_ee_data, + this.m_ee_makePacket, this.m_ee_sha1, this.m_ee_hmacSha1, this.m_ee_crypt)); + this.m_ee_server.attachCommand( + new ErrorGet(AppConfig.A7_ORD_ERROR_GET, this.m_ee_data, this.m_ee_makePacket, this.m_ee_sha1)); + this.m_ee_server.attachCommand( + new LvEnable(AppConfig.A7_ORD_LV_ENABLE, this.m_ee_data, this.m_ee_makePacket, this.m_ee_sha1)); + this.m_ee_server.attachCommand(new EepInit(AppConfig.A7_ORD_EEP_INIT, this.m_ee_data, this.m_ee_makePacket, + this.m_ee_sha1, this.m_ee_hmacSha1, this.m_ee_crypt)); + this.m_ee_server.attachCommand( + new VerGet(AppConfig.A7_ORD_VER_GET, this.m_ee_data, this.m_ee_makePacket, this.m_ee_sha1)); + this.m_ee_server.attachCommand(new PrivkeyModulusWrite(AppConfig.A7_ORD_GPRIKEY_MODULUS_WRITE, this.m_ee_data, + this.m_ee_makePacket, this.m_ee_sha1, this.m_ee_hmacSha1, this.m_ee_crypt)); + this.m_ee_server.attachCommand(new PrikeyExponentWrite(AppConfig.A7_ORD_GPRIKEY_EXPONENS_WRITE, this.m_ee_data, + this.m_ee_makePacket, this.m_ee_sha1, this.m_ee_hmacSha1, this.m_ee_crypt)); + this.m_ee_server.attachCommand(new UdataWrite(AppConfig.A7_ORD_UDATA_WRITE, this.m_ee_data, + this.m_ee_makePacket, this.m_ee_sha1, this.m_ee_hmacSha1, this.m_ee_crypt)); + this.m_ee_server.attachCommand(new UdataRead(AppConfig.A7_ORD_UDATA_READ, this.m_ee_data, this.m_ee_makePacket, + this.m_ee_sha1, this.m_ee_hmacSha1, this.m_ee_crypt)); + this.m_ee_server.attachCommand(new StorageWrite(AppConfig.A7_ORD_STORAGE_WRITE, this.m_ee_data, + this.m_ee_makePacket, this.m_ee_sha1, this.m_ee_hmacSha1, this.m_ee_crypt)); + this.m_ee_server.attachCommand(new StorageRead(AppConfig.A7_ORD_STORAGE_READ, this.m_ee_data, + this.m_ee_makePacket, this.m_ee_sha1, this.m_ee_hmacSha1, this.m_ee_crypt)); + this.m_ee_server.attachCommand(new RanGet(AppConfig.A7_ORD_RAN_GET, this.m_ee_data, this.m_ee_makePacket, + this.m_ee_sha1, this.m_ee_hmacSha1, this.m_ee_crypt, this.m_ee_random)); + this.m_ee_server.attachCommand(new PlayCountIncrement(AppConfig.A7_ORD_PLAY_COUNT_INCREMENT, this.m_ee_data, + this.m_ee_makePacket, this.m_ee_sha1, this.m_ee_hmacSha1, this.m_ee_crypt)); + this.m_ee_server.attachCommand(new PlayCountRead(AppConfig.A7_ORD_PLAY_COUNT_READ, this.m_ee_data, + this.m_ee_makePacket, this.m_ee_sha1, this.m_ee_hmacSha1, this.m_ee_crypt, this.m_ee_random)); + this.m_ee_server.attachCommand(new TraceDataInfoWrite(AppConfig.A7_ORD_TRACE_DATA_INFO_WRITE, this.m_ee_data, + this.m_ee_makePacket, this.m_ee_sha1, this.m_ee_hmacSha1, this.m_ee_crypt)); + this.m_ee_server.attachCommand(new TraceDataInfoRead(AppConfig.A7_ORD_TRACE_DATA_INFO_READ, this.m_ee_data, + this.m_ee_makePacket, this.m_ee_sha1, this.m_ee_hmacSha1, this.m_ee_crypt)); + this.m_ee_server.attachCommand(new StorageSizeGet(AppConfig.A7_ORD_STORAGE_SIZE_GET, this.m_ee_data, + this.m_ee_makePacket, this.m_ee_sha1, this.m_ee_hmacSha1, this.m_ee_crypt, this.m_ee_random)); + } + + private short makeErrorPacket(short error, short cmd, byte[] sendPacket, short packetOffset, short packetLength) { + this.m_ee_data.setLastError_ramD((short) error); + this.m_ee_makePacket.setData(null, (short) 0, (short) 0, AppConfig.A7_TAG_RSP_COMMAND, + (short) 26, + (short) error, (short) cmd, null, (short) 0, (short) 0, null, (short) 0, + (short) 0, null, + (short) 0, (short) 0, sendPacket, packetOffset, packetLength, + this.m_ee_sha1, null); + return 26; + } + + public void process(APDU apdu) { + short ramD_sendSize = (short) 0; + if (selectingApplet()) + return; + byte[] ramD_packetData = apdu.getBuffer(); + if (this.m_ee_data.getSflag_ee() && this.m_ee_data.getLevel_ramD() == -1) + return; + + if (this.m_ee_data.getLevel_ramD() == 0) + this.m_ee_data.setLevel_ramD((byte) 1); + + short ramD_length = Util.getShort(ramD_packetData, (short) 5); + boolean ramD_bRet = this.m_ee_buffer.setData_ramD(ramD_packetData, (short) 7, ramD_length); + if (!ramD_bRet) { + this.m_ee_buffer.clear_ramD(); + ramD_sendSize = makeErrorPacket(AppConfig.A7_FAIL, (short) 0, ramD_packetData, (short) 0, (short)ramD_packetData.length); + apdu.setOutgoingAndSend((short) 0, (short) ramD_sendSize); + return; + } + + byte[] ramD_buffer = this.m_ee_buffer.getBuffer_ramD(); + short ramD_size = Util.getShort(ramD_buffer, AppConfig.A7_PARAMSIZE_OFFSET); + if (ramD_size > this.m_ee_buffer.getBufferSize_ramD()) + return; + + try { + ramD_sendSize = this.m_ee_server.execute(ramD_buffer, (short) 0, this.m_ee_buffer.getBufferSize_ramD(), ramD_packetData, (short) 0, (short) ramD_packetData.length); + } catch (Exception e) { + short ramD_cmd = Util.getShort(ramD_buffer, AppConfig.A7_COMMAND_OFFSET); + this.m_ee_data.setLastError_ramD(AppConfig.A7_FAIL); + ramD_sendSize = makeErrorPacket(AppConfig.A7_FAIL, ramD_cmd, ramD_packetData, (short) 0, (short) ramD_packetData.length); + } + + this.m_ee_buffer.clear_ramD(); + if (ramD_sendSize != 0) + apdu.setOutgoingAndSend((short) 0, ramD_sendSize); + } + + public static void install(byte[] bArray, short bOffset, byte bLength) { + (new PrivkeyModulusWrite()).register(bArray, (short) ((short) bOffset + 1), + bArray[(short) bOffset]); + } + + public void deselect() { + super.deselect(); + } +} diff --git a/src/sega/a7/AppBuffer.java b/src/sega/a7/AppBuffer.java new file mode 100644 index 0000000..aabea65 --- /dev/null +++ b/src/sega/a7/AppBuffer.java @@ -0,0 +1,36 @@ +package sega.a7; + +import javacard.framework.JCSystem; +import javacard.framework.Util; + +public class AppBuffer { + private static final short BUFFER_SIZE = 416; + + private short[] m_ramD_size = JCSystem.makeTransientShortArray((short) 1, (byte) 1); + private byte[] m_ramD_buffer = JCSystem.makeTransientByteArray(BUFFER_SIZE, (byte) 1); + + public AppBuffer() { + this.m_ramD_size[0] = 0; + } + + public byte[] getBuffer_ramD() { + return this.m_ramD_buffer; + } + + public short getBufferSize_ramD() { + return this.m_ramD_size[0]; + } + + public boolean setData_ramD(byte[] data, short offset, short length) { + if (this.m_ramD_size[0] + length > this.m_ramD_buffer.length) + return false; + + Util.arrayCopyNonAtomic(data, offset, this.m_ramD_buffer, this.m_ramD_size[0], length); + this.m_ramD_size[0] = (short) (this.m_ramD_size[0] + length); + return true; + } + + public void clear_ramD() { + this.m_ramD_size[0] = 0; + } +} diff --git a/src/sega/a7/AppConfig.java b/src/sega/a7/AppConfig.java new file mode 100644 index 0000000..9fad873 --- /dev/null +++ b/src/sega/a7/AppConfig.java @@ -0,0 +1,94 @@ +package sega.a7; + +public interface AppConfig { + public static final short VERSION = 0x0205; + + public static final short HEADER_SIZE = 6; + public static final short FOOTER_SIZE = 40; + + public static final short NONCE_ODD_SIZE = 20; + public static final short NONCE_EVEN_SIZE = 20; + public static final short HMAC_SIZE = 20; + public static final short AES_KEY_SIZE = 0x10; + public static final short AES_IV_SIZE = 0x10; + public static final short AES_DATA_SIZE = 0x10; + public static final short RSA_PRI_MODULUS_SIZE = 0x100; + public static final short RSA_PRI_EXPONENT_SIZE = 0x100; + public static final short UDATA_SIZE = 0x10; + public static final short PLAY_COUNT_VALUE_SIZE = 4; + public static final short STORAGE_SIZE = 0x2800; + public static final short STORAGE_SURPLUS_SIZE = 0x10; + public static final short KEYCHIP_INFO_SIZE = 96; + public static final short TRACE_DATA_INFO_SIZE = 0x10; + public static final short STORAGE_DATA_MAX_READ_SIZE = 192; + + public static final short A7_TAG_OFFSET = 0; + public static final short A7_PARAMSIZE_OFFSET = 2; + public static final short A7_COMMAND_OFFSET = 4; + public static final short A7_TAG_SIZE = 2; + public static final short A7_PARAMSIZE_SIZE = 2; + public static final short A7_COMMAND_SIZE = 2; + public static final short A7_CHECKSUM_SIZE = 20; + public static final short A7_AUTH_SIZE = 20; + + // Tag codes + public static final short A7_TAG_RQU_COMMAND = 0xC1; + public static final short A7_TAG_RQU_AUTH_COMMAND = 0xC2; + public static final short A7_TAG_RSP_COMMAND = 0xC3; + public static final short A7_TAG_RSP_AUTH_COMMAND = 0xC4; + public static final short A7_TAG_RQU_RSA_COMMAND = 0xC5; + public static final short A7_TAG_RSP_RSA_COMMAND = 0xC6; + public static final short A7_TAG_NG = 0; + + // cmd codes + public static final short A7_ORD_SESSION_OPEN = 1; + public static final short A7_ORD_SESSION_CLOSE = 2; + public static final short A7_ORD_AUTH_START = 3; + public static final short A7_ORD_HMAC_CHANGE = 4; + public static final short A7_ORD_KEY_CHANGE = 5; + public static final short A7_ORD_LV_GET = 6; + public static final short A7_ORD_ERROR_GET = 7; + public static final short A7_ORD_VER_GET = 8; + public static final short A7_ORD_KEYCHIP_INFO_WRITE = 9; + public static final short A7_ORD_KEYCHIP_INFO_READ = 10; + public static final short A7_ORD_GKEY_WRITE = 11; + public static final short A7_ORD_GKEY_ENC = 12; + public static final short A7_ORD_GKEY_DEC = 13; + public static final short A7_ORD_SFLAG_WRITE = 14; + public static final short A7_ORD_EEP_INIT = 15; + public static final short A7_ORD_LV_ENABLE = 16; + public static final short A7_ORD_GPRIKEY_MODULUS_WRITE = 17; + public static final short A7_ORD_GPRIKEY_EXPONENS_WRITE = 18; + public static final short A7_ORD_UDATA_WRITE = 19; + public static final short A7_ORD_UDATA_READ = 20; + public static final short A7_ORD_STORAGE_WRITE = 21; + public static final short A7_ORD_STORAGE_READ = 22; + public static final short A7_ORD_RAN_GET = 23; + public static final short A7_ORD_PLAY_COUNT_INCREMENT = 24; + public static final short A7_ORD_PLAY_COUNT_READ = 25; + public static final short A7_ORD_TRACE_DATA_INFO_WRITE = 26; + public static final short A7_ORD_TRACE_DATA_INFO_READ = 27; + public static final short A7_ORD_STORAGE_SIZE_GET = 28; + + //Errors + public static final short A7_SUCCESS = 0; + public static final short A7_INVALID_AUTH = 1; + public static final short A7_AUTHFAIL = 2; + public static final short A7_LV_ERROR = 3; + public static final short A7_BAD_PARAMETER = 4; + public static final short A7_EEP_WRITEFAIL = 5; + public static final short A7_BAD_TAG = 6; + public static final short A7_BAD_ORDINAL = 7; + public static final short A7_SUMFAIL = 8; + public static final short A7_EEPWRITE_DISABLE = 9; + public static final short A7_BAD_DATASIZE = 10; + public static final short A7_FAIL = 11; + + public static final short GENERAL_BUFFER_SIZE = 0x100; + public static final short FOOTER_BUFFER_SIZE = 20; + public static final short NONCE_ODD_BUFFER_SIZE = 20; + public static final short SEND_OUT_BUFFER_SIZE = 0x100; + public static final short SEND_BUUFER_INFO_ARRAY_SIZE = 2; + public static final short SEND_BUUFER_INFO_OFFSET = 0; + public static final short SEND_BUUFER_INFO_SIZE = 1; +} diff --git a/src/sega/a7/AppData.java b/src/sega/a7/AppData.java new file mode 100644 index 0000000..5b57a11 --- /dev/null +++ b/src/sega/a7/AppData.java @@ -0,0 +1,429 @@ +package sega.a7; + +import javacard.framework.JCSystem; +import javacard.framework.Util; +import javacard.security.RandomData; + +public class AppData { + /** + * 9FD0A43A697329C54BAEC33CF07303BB25F4EB0F366B214633D48ABF639C1057 + * 55BD87F4071A20E5A139DCF283C86DE5E4D13DA34A023E21AC1B27A452C49044 + * 97E625C32F6F9762BB80235D11D592965EA6F5839586C3066F2079E70C96055A + * FC5A7FC25789B54DB0833D3625B8DAE173A127A681CCE210103BB72FD0205CD3 + * F024C1BB26E261664D638390F8EF7D512DCF2BC72A826EEC413F233788BA1309 + * 264018EFDBD8CB748E08917C992A67B7B2C0357E45AB9C9E51CF308EFCC0256F + * 28999B079BBB3ADF67D7221A1DE8F3F587A1A49662E0DFE6F5FA557351F04779 + * 3FCE52641D2C7DC6B0EABA8AE529D1DFF4DC793BB82994CB49B6E4EFD80F142B + */ + private static final byte[] m_ee_defaultPriModulus = new byte[] { + -97, -48, -92, 58, 105, 115, 41, -59, 75, -82, + -61, 60, -16, 115, 3, -69, 37, -12, -21, 15, + 54, 107, 33, 70, 51, -44, -118, -65, 99, -100, + 16, 87, 85, -67, -121, -12, 7, 26, 32, -27, + -95, 57, -36, -14, -125, -56, 109, -27, -28, -47, + 61, -93, 74, 2, 62, 33, -84, 27, 39, -92, + 82, -60, -112, 68, -105, -26, 37, -61, 47, 111, + -105, 98, -69, -128, 35, 93, 17, -43, -110, -106, + 94, -90, -11, -125, -107, -122, -61, 6, 111, 32, + 121, -25, 12, -106, 5, 90, -4, 90, 127, -62, + 87, -119, -75, 77, -80, -125, 61, 54, 37, -72, + -38, -31, 115, -95, 39, -90, -127, -52, -30, 16, + 16, 59, -73, 47, -48, 32, 92, -45, -16, 36, + -63, -69, 38, -30, 97, 102, 77, 99, -125, -112, + -8, -17, 125, 81, 45, -49, 43, -57, 42, -126, + 110, -20, 65, 63, 35, 55, -120, -70, 19, 9, + 38, 64, 24, -17, -37, -40, -53, 116, -114, 8, + -111, 124, -103, 42, 103, -73, -78, -64, 53, 126, + 69, -85, -100, -98, 81, -49, 48, -114, -4, -64, + 37, 111, 40, -103, -101, 7, -101, -69, 58, -33, + 103, -41, 34, 26, 29, -24, -13, -11, -121, -95, + -92, -106, 98, -32, -33, -26, -11, -6, 85, 115, + 81, -16, 71, 121, 63, -50, 82, 100, 29, 44, + 125, -58, -80, -22, -70, -118, -27, 41, -47, -33, + -12, -36, 121, 59, -72, 41, -108, -53, 73, -74, + -28, -17, -40, 15, 20, 43 + }; + + /** + * 310A06BADDCCB6CE91B0A8BC3454369AE0C4CCB438509B3F3D7C44AF01D3CBB7 + * E0D96DB455D190B2A5CC699E090E219ADFA1CD3623E9984320DA9C4972145AE8 + * 916BCFBE9AF9B50C58D8B301460DB1136F2BF03E564DA9DE798F0F98F465BC72 + * F4E898377C41075F3580AFF1C3957BA49EA49ED41B145171F8693A86F3685AD3 + * 39BEFDA3188141990787977FD8BE7D588886A67E4EEBEB38FBB09FAF44468FF9 + * EF74BB7961ED1063714CCA6ECAEC8389CE4A6F315C3069EA4BF2F6CAEF2028A2 + * 09B0307200475F775CCAD248E2E93C42C312F954183D233EB1B29409388C03E6 + * 2961A8833F5A508305B7D8013AABE6CD1A01034A18E4438DCD46A52825F539F1 + */ + private static final byte[] m_ee_defaultPriExponent = new byte[] { + 49, 10, 6, -70, -35, -52, -74, -50, -111, -80, + -88, -68, 52, 84, 54, -102, -32, -60, -52, -76, + 56, 80, -101, 63, 61, 124, 68, -81, 1, -45, + -53, -73, -32, -39, 109, -76, 85, -47, -112, -78, + -91, -52, 105, -98, 9, 14, 33, -102, -33, -95, + -51, 54, 35, -23, -104, 67, 32, -38, -100, 73, + 114, 20, 90, -24, -111, 107, -49, -66, -102, -7, + -75, 12, 88, -40, -77, 1, 70, 13, -79, 19, + 111, 43, -16, 62, 86, 77, -87, -34, 121, -113, + 15, -104, -12, 101, -68, 114, -12, -24, -104, 55, + 124, 65, 7, 95, 53, -128, -81, -15, -61, -107, + 123, -92, -98, -92, -98, -44, 27, 20, 81, 113, + -8, 105, 58, -122, -13, 104, 90, -45, 57, -66, + -3, -93, 24, -127, 65, -103, 7, -121, -105, 127, + -40, -66, 125, 88, -120, -122, -90, 126, 78, -21, + -21, 56, -5, -80, -97, -81, 68, 70, -113, -7, + -17, 116, -69, 121, 97, -19, 16, 99, 113, 76, + -54, 110, -54, -20, -125, -119, -50, 74, 111, 49, + 92, 48, 105, -22, 75, -14, -10, -54, -17, 32, + 40, -94, 9, -80, 48, 114, 0, 71, 95, 119, + 92, -54, -46, 72, -30, -23, 60, 66, -61, 18, + -7, 84, 24, 61, 35, 62, -79, -78, -108, 9, + 56, -116, 3, -26, 41, 97, -88, -125, 63, 90, + 80, -125, 5, -73, -40, 1, 58, -85, -26, -51, + 26, 1, 3, 74, 24, -28, 67, -115, -51, 70, + -91, 40, 37, -11, 57, -15 + }; + + private static final byte VALUE_AUTH_LEVEL = 0; + private static final byte VALUE_SESSION = 1; + private static final byte VALUE_ERROR_RESULT_H = 2; + private static final byte VALUE_ERROR_COUNT = 4; + private static final byte VALUE_WRITE_FLAG = 5; + private static final byte VALUE_SIZE = 6; + + private byte[] m_ee_sflag = new byte[1]; + private byte[] m_ramD_rsa_update_status; + private byte[] m_ramD_value; + private byte[] m_ramD_kh; + private byte[] m_ramD_cryptBuffer; + private byte[] m_ee_gkeyIv; + private byte[] m_ramD_cKeyIv; + private byte[] m_ramD_newNonceEvent; + private byte[] m_ramD_lastNonceEvent; + private byte[] m_ramD_generalBuffer; + private byte[] m_ramD_sendOutBuffer; + private short[] m_ramD_sendOutInfo; + private byte[] m_ramD_footerBuffer; + private byte[] m_ramD_nonceOddBuffer; + private byte[] m_ee_priModulus = new byte[AppConfig.RSA_PRI_MODULUS_SIZE]; + private byte[] m_ee_priExponent = new byte[AppConfig.RSA_PRI_EXPONENT_SIZE]; + private byte[] m_ee_udata = new byte[AppConfig.UDATA_SIZE]; + private byte[] m_ee_storage = new byte[AppConfig.STORAGE_SIZE]; + private byte[] m_ee_keychipInfo = new byte[AppConfig.KEYCHIP_INFO_SIZE]; + private byte[] m_ee_traceDataInfo = new byte[AppConfig.TRACE_DATA_INFO_SIZE]; + private byte[] m_ee_playCount = new byte[AppConfig.PLAY_COUNT_VALUE_SIZE]; + private RandomData m_ee_rand; + + public static final byte SESSION_DISABLE = 0; + public static final byte SESSION_ENABLE = 1; + public static final byte SHIPMENT_FLAG = 0x04; + public static final byte BLOCK_FLAG = 0x20; + public static final byte RSA_UPDATE_FLAG = 1; + public static final byte RSA_UPDATE_STATUS_SIZE = 1; + public static final byte RSA_UPDATE_EXPONENT = 0x08; + public static final byte RSA_UPDATE_MODULUS = 0x40; + + public AppData(RandomData rand) { + this.m_ee_rand = rand; + this.m_ee_gkeyIv = new byte[16]; + Util.arrayCopy(m_ee_defaultPriModulus, (short) 0, this.m_ee_priModulus, (short) 0, + (short) this.m_ee_priModulus.length); + Util.arrayCopy(m_ee_defaultPriExponent, (short) 0, this.m_ee_priExponent, (short) 0, + (short) this.m_ee_priExponent.length); + this.m_ee_sflag[0] = 0; + + Util.arrayFillNonAtomic(this.m_ee_keychipInfo, (short) 0, (short) this.m_ee_keychipInfo.length, (byte) -1); + Util.arrayFillNonAtomic(this.m_ee_udata, (short) 0, (short) this.m_ee_udata.length, (byte) -1); + Util.arrayFillNonAtomic(this.m_ee_storage, (short) 0, (short) this.m_ee_storage.length, (byte) -1); + Util.arrayFillNonAtomic(this.m_ee_traceDataInfo, (short) 0, (short) this.m_ee_traceDataInfo.length, (byte) -1); + Util.arrayFillNonAtomic(this.m_ee_playCount, (short) 0, (short) this.m_ee_playCount.length, (byte) 0); + Util.arrayFillNonAtomic(this.m_ee_gkeyIv, (short) 0, (short) this.m_ee_gkeyIv.length, (byte) -1); + + this.m_ramD_value = JCSystem.makeTransientByteArray(VALUE_SIZE, (byte) 1); + this.m_ramD_rsa_update_status = JCSystem.makeTransientByteArray(RSA_UPDATE_STATUS_SIZE, (byte) 1); + this.m_ramD_kh = JCSystem.makeTransientByteArray((short) 20, (byte) 1); + this.m_ramD_newNonceEvent = JCSystem.makeTransientByteArray((short) 20, (byte) 1); + this.m_ramD_lastNonceEvent = JCSystem.makeTransientByteArray((short) 20, (byte) 1); + this.m_ramD_cKeyIv = JCSystem.makeTransientByteArray(AppConfig.AES_IV_SIZE, (byte) 1); + this.m_ramD_generalBuffer = JCSystem.makeTransientByteArray(AppConfig.GENERAL_BUFFER_SIZE, (byte) 1); + this.m_ramD_footerBuffer = JCSystem.makeTransientByteArray(AppConfig.FOOTER_BUFFER_SIZE, (byte) 1); + this.m_ramD_nonceOddBuffer = JCSystem.makeTransientByteArray(AppConfig.NONCE_ODD_BUFFER_SIZE, (byte) 1); + this.m_ramD_sendOutBuffer = JCSystem.makeTransientByteArray(AppConfig.SEND_OUT_BUFFER_SIZE, (byte) 1); + this.m_ramD_sendOutInfo = JCSystem.makeTransientShortArray(AppConfig.SEND_BUUFER_INFO_ARRAY_SIZE, (byte) 1); + this.m_ramD_cryptBuffer = JCSystem.makeTransientByteArray((short) 16, (byte) 1); + } + + public void init() { + if (getBlockFlag_ee()) { + this.m_ramD_value[VALUE_AUTH_LEVEL] = -1; + } else { + this.m_ramD_value[VALUE_AUTH_LEVEL] = 0; + } + this.m_ramD_value[VALUE_SESSION] = SESSION_DISABLE; + this.m_ramD_value[VALUE_ERROR_COUNT] = 0; + } + + public void reset() { + this.m_ee_sflag[0] = 0; + Util.arrayFillNonAtomic(this.m_ee_keychipInfo, (short) 0, (short) this.m_ee_keychipInfo.length, (byte) -1); + Util.arrayFillNonAtomic(this.m_ee_udata, (short) 0, (short) this.m_ee_udata.length, (byte) -1); + Util.arrayFillNonAtomic(this.m_ee_storage, (short) 0, (short) this.m_ee_storage.length, (byte) -1); + Util.arrayFillNonAtomic(this.m_ee_traceDataInfo, (short) 0, (short) this.m_ee_traceDataInfo.length, (byte) -1); + Util.arrayFillNonAtomic(this.m_ee_playCount, (short) 0, (short) this.m_ee_playCount.length, (byte) 0); + Util.arrayFillNonAtomic(this.m_ee_gkeyIv, (short) 0, (short) this.m_ee_gkeyIv.length, (byte) -1); + } + + public void setLevel_ramD(byte setLevel) { + this.m_ramD_value[VALUE_AUTH_LEVEL] = setLevel; + } + + public byte getLevel_ramD() { + return this.m_ramD_value[VALUE_AUTH_LEVEL]; + } + + public void setSession_ramD(byte setSession) { + this.m_ramD_value[VALUE_SESSION] = setSession; + } + + public void addValuePlayCounter_ee(byte value) { + short ramD_tmp = 0; + short ramD_setValue = (short) value; + short ramD_ii = 0; + + while (ramD_ii < this.m_ee_playCount.length) { + short ramD_index = (short) ((this.m_ee_playCount.length - ramD_ii) - 1); + ramD_tmp = (short) ((ramD_setValue & 0xFF) + (this.m_ee_playCount[ramD_index] & 0xFF)); + this.m_ee_playCount[ramD_index] = (byte) (ramD_tmp & 0xFF); + + if (ramD_tmp > 255) { + ramD_setValue = 1; + ramD_ii++; + continue; + } + break; + } + } + + public boolean getPlayCounter_ee(byte[] playCount, short offset, short length) { + if (length < this.m_ee_playCount.length) + return false; + + Util.arrayCopyNonAtomic(this.m_ee_playCount, (short) 0, playCount, offset, (short) this.m_ee_playCount.length); + return true; + } + + public byte getSession_ramD() { + return this.m_ramD_value[VALUE_SESSION]; + } + + public final byte[] getNewNonceEvent_ramD() { + this.m_ee_rand.generateData(this.m_ramD_newNonceEvent, (short) 0, + (short) this.m_ramD_newNonceEvent.length); + return this.m_ramD_newNonceEvent; + } + + public final byte[] getLastNonceEvent_ramD() { + return this.m_ramD_lastNonceEvent; + } + + public boolean setLastNonceEvent_ramD(byte[] lastNonceEvent, short offset, short length) { + if (length > this.m_ramD_lastNonceEvent.length) + return false; + + short ramD_writeSize = Util.arrayCopyNonAtomic(lastNonceEvent, offset, this.m_ramD_lastNonceEvent, (short) 0, + length); + return ramD_writeSize == length; + } + + public final byte[] getKh_ramD() { + return this.m_ramD_kh; + } + + public boolean setKh_ramD(byte[] kh, short offset, short length) { + if (length > this.m_ramD_kh.length) + return false; + + short ramD_writeSize = Util.arrayCopyNonAtomic(kh, offset, this.m_ramD_kh, (short) 0, length); + return ramD_writeSize == length; + } + + public final byte[] getGkeyIv_ee() { + return this.m_ee_gkeyIv; + } + + public boolean setGkeyIv_ee(byte[] newGkeyIv, short offset, short length) { + if (length > this.m_ee_gkeyIv.length) + return false; + short ramD_writeSize = Util.arrayCopy(newGkeyIv, offset, this.m_ee_gkeyIv, (short) 0, length); + return ramD_writeSize == length; + } + + public final byte[] getCkeyIv_ramD() { + return this.m_ramD_cKeyIv; + } + + public boolean setCkeyIv_ramD(byte[] newCkeyIv, short offset, short length) { + if (length > this.m_ee_gkeyIv.length) + return false; + short ramD_writeSize = Util.arrayCopyNonAtomic(newCkeyIv, offset, this.m_ramD_cKeyIv, (short) 0, length); + return ramD_writeSize == length; + } + + public final byte[] getRsaDefaultPriModulus_ee() { + return m_ee_defaultPriModulus; + } + + public final byte[] getRsaDefaultPriExponent_ee() { + return m_ee_defaultPriExponent; + } + + public final byte[] getRsaPriModulus_ee() { + return this.m_ee_priModulus; + } + + public final byte[] getRsaPriExponent_ee() { + return this.m_ee_priExponent; + } + + public boolean setRsaPriKeyModulus_ee(byte[] exponent, short eOfset, short eLength) { + if (eLength > this.m_ee_priModulus.length) + return false; + + short ramD_writeSize = Util.arrayCopy(exponent, eOfset, this.m_ee_priModulus, (short) 0, eLength); + return ramD_writeSize == eLength; + } + + public boolean setRsaPriKeyExponent_ee(byte[] modulus, short mOffset, short mLength) { + if (mLength > this.m_ee_priExponent.length) + return false; + + short ramD_writeSize = Util.arrayCopy(modulus, mOffset, this.m_ee_priExponent, (short) 0, mLength); + return ramD_writeSize == mLength; + } + + public boolean getSflag_ee() { + return (this.m_ee_sflag[0] & SHIPMENT_FLAG) != 0; + } + + public void activeSflag() { + this.m_ramD_value[VALUE_WRITE_FLAG] = this.m_ee_sflag[0]; + this.m_ramD_value[VALUE_WRITE_FLAG] |= SHIPMENT_FLAG; + Util.arrayCopy(this.m_ramD_value, VALUE_WRITE_FLAG, this.m_ee_sflag, (short) 0, (short) 1); + } + + public boolean getRsaExponentUpdate_ramD() { + return (this.m_ramD_rsa_update_status[0] & RSA_UPDATE_EXPONENT) != 0; + } + + public void activeRssaExponentUpdate_ramD() { + this.m_ramD_rsa_update_status[0] = (byte) (this.m_ramD_rsa_update_status[0] | RSA_UPDATE_EXPONENT); + } + + public boolean getRsaModulusUpdate_ramD() { + return (this.m_ramD_rsa_update_status[0] & RSA_UPDATE_MODULUS) != 0; + } + + public void activeRssaModulusUpdate_ramD() { + this.m_ramD_rsa_update_status[0] = (byte) (this.m_ramD_rsa_update_status[0] | RSA_UPDATE_MODULUS); + } + + public boolean getBlockFlag_ee() { + return (this.m_ee_sflag[0] & BLOCK_FLAG) != 0; + } + + public void activeBlockFlag() { + this.m_ramD_value[VALUE_WRITE_FLAG] = this.m_ee_sflag[0]; + this.m_ramD_value[VALUE_WRITE_FLAG] |= BLOCK_FLAG; + Util.arrayCopy(this.m_ramD_value, VALUE_WRITE_FLAG, this.m_ee_sflag, (short) 0, (short) 1); + } + + public final byte[] getKeychipInfo_ee() { + return this.m_ee_keychipInfo; + } + + public boolean setKeychipInfo_ee(byte[] newKeychipInfo, short offset, short length) { + if (length > this.m_ee_keychipInfo.length) + return false; + short ramD_writeSize = Util.arrayCopy(newKeychipInfo, offset, this.m_ee_keychipInfo, (short) 0, length); + return ramD_writeSize == length; + } + + public final byte[] getTraceDataInfo_ee() { + return this.m_ee_traceDataInfo; + } + + public boolean setTraceDataInfo_ee(byte[] newTraceDataInfo, short offset, short length) { + if (length > this.m_ee_traceDataInfo.length) + return false; + + short ramD_writeSize = Util.arrayCopy(newTraceDataInfo, offset, this.m_ee_traceDataInfo, (short) 0, length); + return ramD_writeSize == length; + } + + public final byte[] getUdata_ee() { + return this.m_ee_udata; + } + + public boolean setUdata_ee(byte[] newUdata, short offset, short length) { + if (length > newUdata.length) + return false; + short ramD_writeSize = Util.arrayCopy(newUdata, offset, this.m_ee_udata, (short) 0, length); + return ramD_writeSize == length; + } + + public final byte[] getStorageData_ee() { + return this.m_ee_storage; + } + + public boolean setStorageData_ee(byte[] newStorage, short offset, short length, short dstOffset) { + if (length > (this.m_ee_storage.length - dstOffset)) + return false; + + short ramD_writeSize = Util.arrayCopy(newStorage, offset, this.m_ee_storage, dstOffset, length); + return ramD_writeSize == (dstOffset + length); + } + + public byte[] getGeneralBuffer_ramD() { + return this.m_ramD_generalBuffer; + } + + public byte[] getSendOutBuffer_ramD() { + return this.m_ramD_sendOutBuffer; + } + + public short[] getSendOutInfo_ramD() { + return this.m_ramD_sendOutInfo; + } + + public byte[] getCryptBuffer_ramD() { + return this.m_ramD_cryptBuffer; + } + + public byte[] getFooterBuffer_ramD() { + return this.m_ramD_footerBuffer; + } + + public byte[] getNonceOddBuffer_ramD() { + return this.m_ramD_nonceOddBuffer; + } + + public void setLastError_ramD(short error) { + Util.setShort(this.m_ramD_value, VALUE_ERROR_RESULT_H, (short) error); + } + + public short getLastError_ramD() { + short ramD_result = Util.getShort(this.m_ramD_value, VALUE_ERROR_RESULT_H); + return ramD_result; + } + + public void incrementErrorCount() { + this.m_ramD_value[VALUE_ERROR_COUNT]++; + if (this.m_ramD_value[VALUE_ERROR_COUNT] + 1 == 3) { + activeBlockFlag(); + this.m_ramD_value[VALUE_AUTH_LEVEL] = -1; + } + } + + public void clearErrorCount() { + this.m_ramD_value[VALUE_ERROR_COUNT] = 0; + } +} diff --git a/src/sega/a7/AuthCommand.java b/src/sega/a7/AuthCommand.java new file mode 100644 index 0000000..4df74ac --- /dev/null +++ b/src/sega/a7/AuthCommand.java @@ -0,0 +1,215 @@ +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; + } +} diff --git a/src/sega/a7/AuthStart.java b/src/sega/a7/AuthStart.java new file mode 100644 index 0000000..e4ed37a --- /dev/null +++ b/src/sega/a7/AuthStart.java @@ -0,0 +1,72 @@ +package sega.a7; + +import javacard.framework.Util; +import javacard.security.MessageDigest; + +public class AuthStart extends AuthCommand { + private static final short RECV_PACKET_SIZE = 302; + private static final byte AUTH_LEVEL = 1; + private static final byte SET_AUTH_LEVEL = 2; + private static final short PARAM_SIZE = 46; + + public AuthStart(short cmd, AppData data, MakePacket packet, MessageDigest sha1, HmacSha1 hmacSha1, Crypt crypt) { + super(cmd, RECV_PACKET_SIZE, (short) 2, AUTH_LEVEL, data, packet, sha1, hmacSha1, crypt); + } + + public short execute(byte[] data, short dataOffset, short dataLength, byte[] dst, short dstOffset, + short dstLength) { + short dataSize = 256; + if (this.m_ee_data.getSession_ramD() != 1) + return makeErrorPacket(AppConfig.A7_INVALID_AUTH, dst, dstOffset, dstLength); + if (this.m_ee_data.getLevel_ramD() != SET_AUTH_LEVEL) + return makeErrorPacket(AppConfig.A7_LV_ERROR, dst, dstOffset, dstLength); + + short error = checkHeader(data, dataOffset, dataLength); + if (error != AppConfig.A7_SUCCESS) + return makeErrorPacket(error, dst, dstOffset, dstLength); + + byte[] newData = this.m_ee_data.getGeneralBuffer_ramD(); + if (dataSize > newData.length) + return makeErrorPacket(AppConfig.A7_FAIL, dst, dstOffset, dstLength); + + short decSize = 0; + try { + decSize = rsaDecData(data, (short) (6 + dataOffset), dataSize, newData, (short) 0); + } catch (Exception e) { + return makeErrorPacket(AppConfig.A7_AUTHFAIL, dst, dstOffset, dstLength); + } + if (decSize < 52) + return makeErrorPacket(AppConfig.A7_AUTHFAIL, dst, dstOffset, dstLength); + + boolean bRet = this.m_ee_data.setKh_ramD(newData, (short) 32, (short) 20); + if (!bRet) + return makeErrorPacket(AppConfig.A7_FAIL, dst, dstOffset, dstLength); + + error = checkFooter(data, dataOffset, dataLength); + if (error != AppConfig.A7_SUCCESS) + return makeErrorPacket(error, dst, dstOffset, dstLength); + bRet = changeConnectionKey_ee(newData, (short) 0, AppConfig.AES_KEY_SIZE, newData, AppConfig.AES_KEY_SIZE, AppConfig.AES_IV_SIZE); + if (!bRet) + return makeErrorPacket(AppConfig.A7_FAIL, dst, dstOffset, dstLength); + + byte[] nonceOdd = this.m_ee_data.getNonceOddBuffer_ramD(); + Util.arrayCopyNonAtomic(data, (short) (262 + dataOffset), nonceOdd, (short) 0, (short) 20); + this.m_ee_data.setLevel_ramD((byte) 2); + return makeSendAuthPacket(AppConfig.A7_TAG_RSP_RSA_COMMAND, PARAM_SIZE, (short) 0, null, (short) 0, + (short) 0, data, (short) (262 + dataOffset), (short) 20, dst, dstOffset, dstLength); + } + + protected short checkHeader(byte[] data, short dataOffset, short dataLength) { + if (dataLength != this.m_ee_recvPacketSize) + return AppConfig.A7_BAD_DATASIZE; + + short tag = Util.getShort(data, (short) (dataOffset + 0)); + if (tag != AppConfig.A7_TAG_RQU_RSA_COMMAND) + return AppConfig.A7_BAD_TAG; + short paramsize = Util.getShort(data, (short) (dataOffset + 2)); + + if (paramsize != this.m_ee_recvPacketSize) + return AppConfig.A7_BAD_DATASIZE; + return AppConfig.A7_SUCCESS; + } +} diff --git a/src/sega/a7/Command.java b/src/sega/a7/Command.java new file mode 100644 index 0000000..87ac2c1 --- /dev/null +++ b/src/sega/a7/Command.java @@ -0,0 +1,135 @@ +package sega.a7; + +import javacard.framework.JCSystem; +import javacard.framework.Util; +import javacard.security.MessageDigest; + +public class Command { + protected short m_ee_cmd; + protected short m_ee_recvPacketSize; + protected short m_ee_sendPacketSize; + protected short[] m_ramD_setSendPacketSize; + protected short m_ee_tag; + protected MakePacket m_ee_packet; + protected AppData m_ee_data; + protected MessageDigest m_ee_sha1; + + private static final short ERROR_PACKET_SIZE = 26; + protected static final short SET_SEND_PACKET_SIZE_ARRAY_SIZE = 1; + + protected byte[] m_ramD_outData; + protected short[] m_ramD_outDataInfo; + + public Command(short cmd, short recvPacketSize, short sendPacketSize, AppData data, MakePacket packet, + MessageDigest sha1) { + this.m_ee_cmd = (short) cmd; + this.m_ee_data = data; + this.m_ee_packet = packet; + this.m_ee_recvPacketSize = (short) recvPacketSize; + this.m_ee_sendPacketSize = (short) sendPacketSize; + this.m_ee_tag = AppConfig.A7_TAG_RQU_COMMAND; + this.m_ee_sha1 = sha1; + this.m_ramD_setSendPacketSize = JCSystem.makeTransientShortArray((short) 1, (byte) 1); + this.m_ramD_setSendPacketSize[0] = this.m_ee_sendPacketSize; + this.m_ramD_outData = data.getSendOutBuffer_ramD(); + this.m_ramD_outDataInfo = data.getSendOutInfo_ramD(); + } + + public boolean select() { + this.m_ramD_setSendPacketSize[0] = this.m_ee_sendPacketSize; + return true; + } + + public short core(byte[] data, short dataOffset, short dataLength) { + return AppConfig.A7_SUCCESS; + } + + public short execute(byte[] data, short dataOffset, short dataLength, byte[] dst, short dstOffset, + short dstLength) { + short ramD_error = checkHeader(data, dataOffset, dataLength); + if (ramD_error != AppConfig.A7_SUCCESS) + return makeErrorPacket(ramD_error, dst, dstOffset, dstLength); + + ramD_error = checkFooter(data, dataOffset, 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, dataOffset, dataLength); + + if (ramD_error != AppConfig.A7_SUCCESS) + return makeErrorPacket(ramD_error, dst, dstOffset, dstLength); + + return makeSendPacket(AppConfig.A7_TAG_RSP_COMMAND, this.m_ramD_setSendPacketSize[0], ramD_error, + this.m_ramD_outData, this.m_ramD_outDataInfo[0], this.m_ramD_outDataInfo[1], + dst, dstOffset, dstLength); + } + + public short getCmd_ee() { + return this.m_ee_cmd; + } + + protected short setSendPacketSize_ramD(short sendSize) { + this.m_ramD_setSendPacketSize[0] = sendSize; + return this.m_ramD_setSendPacketSize[0]; + } + + /** + * Validate packet header. + * The header is 6 bytes. + * 2 bytes: tag + * 2 bytes: paramsize + * 2 bytes: command + */ + protected short checkHeader(byte[] data, short dataOfset, short dataLength) { + short ramD_paramsize = Util.getShort(data, (short) (dataOfset + AppConfig.A7_PARAMSIZE_OFFSET)); + if (dataLength != ramD_paramsize) + return AppConfig.A7_BAD_DATASIZE; + + short ramD_tag = Util.getShort(data, (short) (dataOfset + AppConfig.A7_TAG_OFFSET)); + + if (ramD_tag != this.m_ee_tag) + return AppConfig.A7_BAD_TAG; + if (this.m_ee_recvPacketSize != 0 && dataLength != this.m_ee_recvPacketSize) + return AppConfig.A7_BAD_DATASIZE; + return AppConfig.A7_SUCCESS; + } + + /** + * Validate an unauthenticated packet footer. + * The footer is a 20 byte SHA1 sum of the packet. + */ + protected short checkFooter(byte[] data, short dataOffset, short dataLength) { + short ramD_paramsize = (short) (dataOffset + dataLength - AppConfig.A7_CHECKSUM_SIZE); + byte[] ramD_buffer = this.m_ee_data.getFooterBuffer_ramD(); + this.m_ee_sha1.reset(); + this.m_ee_sha1.doFinal(data, dataOffset, (short) (dataLength - AppConfig.A7_CHECKSUM_SIZE), ramD_buffer, + (short) 0); + if (Util.arrayCompare(data, ramD_paramsize, ramD_buffer, (short) 0, (short) AppConfig.A7_CHECKSUM_SIZE) != 0) + return AppConfig.A7_SUMFAIL; + return AppConfig.A7_SUCCESS; + } + + protected short makeSendPacket(short tag, short paramSize, short result, + byte[] data, short dataOffset, short dataSize, byte[] sendPacket, short packetOffset, + short packetLength) { + if (!this.m_ee_packet.setData(null, (short) 0, (short) 0, tag, paramSize, result, this.m_ee_cmd, data, + dataOffset, + dataSize, null, (short) 0, (short) 0, null, (short) 0, (short) 0, sendPacket, packetOffset, + packetLength, + this.m_ee_sha1, null)) { + return makeErrorPacket(AppConfig.A7_FAIL, sendPacket, packetOffset, packetLength); + } + return paramSize; + } + + protected short makeErrorPacket(short error, byte[] sendPacket, short packetOffset, short packetLength) { + this.m_ee_data.setLastError_ramD(error); + this.m_ee_packet.setData(null, (short) 0, (short) 0, AppConfig.A7_TAG_RSP_COMMAND, ERROR_PACKET_SIZE, + error, this.m_ee_cmd, null, (short) 0, (short) 0, null, (short) 0, (short) 0, + null, (short) 0, (short) 0, sendPacket, packetOffset, packetLength, + this.m_ee_sha1, null); + return ERROR_PACKET_SIZE; + } +} diff --git a/src/sega/a7/CommandServer.java b/src/sega/a7/CommandServer.java new file mode 100644 index 0000000..d1817c2 --- /dev/null +++ b/src/sega/a7/CommandServer.java @@ -0,0 +1,55 @@ +package sega.a7; + +import javacard.framework.Util; + +public class CommandServer { + private Command m_ee_noCommand = null; + private Command[] m_ee_list = new Command[4]; + private short m_ee_listCount = 0; + + public void setNoCommand(Command cmdClass) { + this.m_ee_noCommand = cmdClass; + } + + public void attachCommand(Command cmdClass) { + if (this.m_ee_listCount >= this.m_ee_list.length) { + Command[] ee_tmpCommand = new Command[this.m_ee_list.length * 2]; + for (short ii = 0; ii < this.m_ee_list.length; ii++) + ee_tmpCommand[ii] = this.m_ee_list[ii]; + this.m_ee_list = ee_tmpCommand; + } + this.m_ee_list[this.m_ee_listCount++] = cmdClass; + } + + public short findCommand(short cmd) { + for (short ramD_ii = 0; ramD_ii < this.m_ee_listCount; ramD_ii++) { + if (this.m_ee_list[ramD_ii].getCmd_ee() == cmd) + return ramD_ii; + } + return -1; + } + + public boolean select() { + boolean ramD_bRet = true; + for (short ramD_ii = 0; ramD_ii < this.m_ee_listCount; ramD_ii++) { + if (!this.m_ee_list[ramD_ii].select()) + ramD_bRet = false; + } + return ramD_bRet; + } + + public short execute(byte[] data, short dataOffset, short dataLength, byte[] dst, short dstOffset, + short dstLength) { + short ramD_cmd = -1; + if (6 <= dataLength) + ramD_cmd = Util.getShort(data, (short) (dataOffset + AppConfig.A7_COMMAND_OFFSET)); + + short damD_list = findCommand(ramD_cmd); + if (damD_list >= 0) + return this.m_ee_list[damD_list].execute(data, dataOffset, dataLength, dst, dstOffset, dstLength); + + if (this.m_ee_noCommand == null) + return -1; + return this.m_ee_noCommand.execute(data, ramD_cmd, dataLength, dst, dstOffset, dstLength); + } +} diff --git a/src/sega/a7/Crypt.java b/src/sega/a7/Crypt.java new file mode 100644 index 0000000..a98bb1d --- /dev/null +++ b/src/sega/a7/Crypt.java @@ -0,0 +1,104 @@ +package sega.a7; + +import javacard.security.AESKey; +import javacard.security.KeyBuilder; +import javacard.security.RSAPrivateKey; +import javacardx.crypto.Cipher; + +public class Crypt { + public static final short AES_MODE_GKEY_ENCRYPT = 0; + public static final short AES_MODE_GKEY_DECRYPT = 1; + public static final short AES_MODE_CKEY_ENCRYPT = 2; + public static final short AES_MODE_CKEY_DECRYPT = 3; + public static final short RSA_MODE_DECRYPT = 4; + + private AESKey m_ee_aesKeyEnc = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, (short) 128, false); + private AESKey m_ee_aesKeyDec = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, (short) 128, false); + + private AESKey m_ee_aesConnectionKeyEnc = (AESKey) KeyBuilder.buildKey(KeyBuilder.ALG_TYPE_RSA_CRT_PRIVATE, + (short) 128, false); + private AESKey m_ee_aesConnectionKeyDec = (AESKey) KeyBuilder.buildKey(KeyBuilder.ALG_TYPE_RSA_CRT_PRIVATE, + (short) 128, false); + + private RSAPrivateKey key_ecf2m = (RSAPrivateKey) KeyBuilder.buildKey(KeyBuilder.ALG_TYPE_EC_F2M_PUBLIC, + (short) 2048, + false); + private Cipher m_ee_cipherRsa = Cipher.getInstance(Cipher.ALG_RSA_PKCS1, false); + + private Cipher m_ee_cipherAesEnc = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false); + private Cipher m_ee_cipherAesDec = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false); + private Cipher m_ee_cipherConnectionAesDec = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false); + private Cipher m_ee_cipherConnectionAesEnc = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false); + + public short doFinal(byte[] src, short srcOffset, short srcLength, byte[] dst, short dstOffset, short which) { + if (srcLength > (src.length - srcOffset)) + return 0; + + switch (which) { + case AES_MODE_GKEY_ENCRYPT: + return this.m_ee_cipherAesEnc.doFinal(src, srcOffset, srcLength, dst, dstOffset); + case AES_MODE_GKEY_DECRYPT: + return this.m_ee_cipherAesDec.doFinal(src, srcOffset, srcLength, dst, dstOffset); + case AES_MODE_CKEY_ENCRYPT: + return this.m_ee_cipherConnectionAesEnc.doFinal(src, srcOffset, srcLength, dst, dstOffset); + case AES_MODE_CKEY_DECRYPT: + return this.m_ee_cipherConnectionAesDec.doFinal(src, srcOffset, srcLength, dst, dstOffset); + case RSA_MODE_DECRYPT: + return this.m_ee_cipherRsa.doFinal(src, srcOffset, srcLength, dst, dstOffset); + } + return 0; + } + + public short update(byte[] src, short srcOffset, short srcLength, byte[] dst, short dstOffset, short mode) { + if (srcLength > (src.length - srcOffset)) + return 0; + + switch (mode) { + case AES_MODE_GKEY_ENCRYPT: + return this.m_ee_cipherAesEnc.update(src, srcOffset, srcLength, dst, dstOffset); + case AES_MODE_GKEY_DECRYPT: + return this.m_ee_cipherAesDec.update(src, srcOffset, srcLength, dst, dstOffset); + case AES_MODE_CKEY_ENCRYPT: + return this.m_ee_cipherConnectionAesEnc.update(src, srcOffset, srcLength, dst, dstOffset); + case AES_MODE_CKEY_DECRYPT: + return this.m_ee_cipherConnectionAesDec.update(src, srcOffset, srcLength, dst, dstOffset); + case RSA_MODE_DECRYPT: + return this.m_ee_cipherRsa.update(src, srcOffset, srcLength, dst, dstOffset); + } + return 0; + } + + public boolean init(byte[] data1, short data1Offset, short data1Length, byte[] data2, short data2Offset, + short data2Length, short mode) { + if (data1Length > (data1.length - data1Offset) || data2Length > (data2.length - data2Offset)) + return false; + + switch (mode) { + case AES_MODE_GKEY_ENCRYPT: + this.m_ee_aesKeyEnc.setKey(data1, data1Offset); + this.m_ee_cipherAesEnc.init(this.m_ee_aesKeyEnc, Cipher.MODE_ENCRYPT, data2, data2Offset, data2Length); + return true; + case AES_MODE_GKEY_DECRYPT: + this.m_ee_aesKeyDec.setKey(data1, data1Offset); + this.m_ee_cipherAesDec.init(this.m_ee_aesKeyDec, Cipher.MODE_DECRYPT, data2, data2Offset, data2Length); + return true; + case AES_MODE_CKEY_ENCRYPT: + this.m_ee_aesConnectionKeyEnc.setKey(data1, data1Offset); + this.m_ee_cipherConnectionAesEnc.init(this.m_ee_aesConnectionKeyEnc, Cipher.MODE_ENCRYPT, data2, + data2Offset, data2Length); + return true; + case AES_MODE_CKEY_DECRYPT: + this.m_ee_aesConnectionKeyDec.setKey(data1, data1Offset); + this.m_ee_cipherConnectionAesDec.init(this.m_ee_aesConnectionKeyDec, Cipher.MODE_DECRYPT, data2, + data2Offset, + data2Length); + return true; + case RSA_MODE_DECRYPT: + this.key_ecf2m.setModulus(data1, data1Offset, data1Length); + this.key_ecf2m.setExponent(data2, data2Offset, data2Length); + this.m_ee_cipherRsa.init(this.key_ecf2m, Cipher.MODE_DECRYPT); + return true; + } + return false; + } +} diff --git a/src/sega/a7/EepInit.java b/src/sega/a7/EepInit.java new file mode 100644 index 0000000..8f41128 --- /dev/null +++ b/src/sega/a7/EepInit.java @@ -0,0 +1,35 @@ +package sega.a7; + +import javacard.framework.Util; +import javacard.security.MessageDigest; + +public class EepInit extends AuthCommand { + private static final short RECV_PACKET_SIZE = 46; + private static final byte AUTH_LEVEL = 2; + private static final short PARAM_SIZE = 46; + + public EepInit(short cmd, AppData data, MakePacket packet, MessageDigest sha1, HmacSha1 hmacSha1, Crypt crypt) { + super(cmd, RECV_PACKET_SIZE, PARAM_SIZE, AUTH_LEVEL, data, packet, sha1, hmacSha1, crypt); + } + + public short core(byte[] data, short dataOffset, short dataLength) { + if (this.m_ee_data.getSflag_ee()) + return AppConfig.A7_EEPWRITE_DISABLE; + + this.m_ee_data.reset(); + byte[] modulus = this.m_ee_data.getRsaDefaultPriModulus_ee(); + byte[] exponent = this.m_ee_data.getRsaDefaultPriExponent_ee(); + byte[] tmp = this.m_ee_data.getCryptBuffer_ramD(); + Util.arrayFillNonAtomic(tmp, (short) 0, (short) tmp.length, (byte) -1); + + if (!this.m_ee_data.setRsaPriKeyExponent_ee(exponent, (short) 0, AppConfig.RSA_PRI_EXPONENT_SIZE)) + return AppConfig.A7_EEP_WRITEFAIL; + + if (!this.m_ee_data.setRsaPriKeyModulus_ee(modulus, (short) 0, AppConfig.RSA_PRI_MODULUS_SIZE)) + return AppConfig.A7_EEP_WRITEFAIL; + + changeRsaKey_ee(modulus, (short) 0, AppConfig.RSA_PRI_MODULUS_SIZE, exponent, (short) 0, AppConfig.RSA_PRI_EXPONENT_SIZE); + changeGKey_ee(tmp, (short) 0, (short) tmp.length, tmp, (short) 0, (short) tmp.length); + return AppConfig.A7_SUCCESS; + } +} diff --git a/src/sega/a7/ErrorGet.java b/src/sega/a7/ErrorGet.java new file mode 100644 index 0000000..6b4153a --- /dev/null +++ b/src/sega/a7/ErrorGet.java @@ -0,0 +1,24 @@ +package sega.a7; + +import javacard.framework.Util; +import javacard.security.MessageDigest; + +public class ErrorGet extends Command { + private static final short RECV_PACKET_SIZE = 26; + private static final short PARAM_SIZE = 28; + + public ErrorGet(short cmd, AppData data, MakePacket packet, MessageDigest sha1) { + super(cmd, RECV_PACKET_SIZE, PARAM_SIZE, data, packet, sha1); + } + + public short core(byte[] data, short dataOffset, short dataLength) { + byte[] ramD_errorBuf = this.m_ee_data.getGeneralBuffer_ramD(); + short ramD_lastError = this.m_ee_data.getLastError_ramD(); + Util.setShort(ramD_errorBuf, (short) 0, ramD_lastError); + this.m_ramD_outDataInfo[0] = 0; + this.m_ramD_outDataInfo[1] = 2; + Util.arrayCopyNonAtomic(ramD_errorBuf, this.m_ramD_outDataInfo[0], this.m_ramD_outData, + this.m_ramD_outDataInfo[0], this.m_ramD_outDataInfo[1]); + return AppConfig.A7_SUCCESS; + } +} diff --git a/src/sega/a7/GkeyDec.java b/src/sega/a7/GkeyDec.java new file mode 100644 index 0000000..bab4a76 --- /dev/null +++ b/src/sega/a7/GkeyDec.java @@ -0,0 +1,44 @@ +package sega.a7; + +import javacard.framework.Util; +import javacard.security.MessageDigest; + +public class GkeyDec extends AuthCommand { + private static final short RECV_PACKET_SIZE = 63; + private static final byte AUTH_LEVEL = 2; + private static final short PARAM_SIZE = 62; + private static final short IV_INIT_OFFSET = 6; + private static final short DATA_OFFSET = 7; + private static final short DATA_SIZE = 16; + + public GkeyDec(short cmd, AppData data, MakePacket packet, MessageDigest sha1, + HmacSha1 hmacSha1, Crypt crypt) { + super(cmd, RECV_PACKET_SIZE, PARAM_SIZE, AUTH_LEVEL, data, packet, sha1, hmacSha1, crypt); + } + + public short core(byte[] data, short dataOffset, short dataLength) { + byte ramD_ivInit = data[dataOffset + IV_INIT_OFFSET]; + byte[] ramD_decData = this.m_ee_data.getGeneralBuffer_ramD(); + boolean bInit = false; + if (ramD_decData.length < 48) + return AppConfig.A7_FAIL; + short ramD_decSize = decData(data, (short) (dataOffset + DATA_OFFSET), DATA_SIZE, ramD_decData, + (short) 0); + if (16 > ramD_decSize) + return AppConfig.A7_FAIL; + + if (1 == ramD_ivInit) + bInit = true; + decUpdate_Gkey(ramD_decData, (short) 0, (short) 16, ramD_decData, (short) 16, bInit); + short ramD_encSize = encData(ramD_decData, (short) 16, (short) 16, ramD_decData, (short) 32); + if (16 != ramD_encSize) + return AppConfig.A7_FAIL; + + this.m_ramD_outDataInfo[0] = 32; + this.m_ramD_outDataInfo[1] = 16; + Util.arrayCopyNonAtomic(ramD_decData, this.m_ramD_outDataInfo[0], this.m_ramD_outData, + this.m_ramD_outDataInfo[0], this.m_ramD_outDataInfo[1]); + + return AppConfig.A7_SUCCESS; + } +} diff --git a/src/sega/a7/GkeyEnc.java b/src/sega/a7/GkeyEnc.java new file mode 100644 index 0000000..f81a7c9 --- /dev/null +++ b/src/sega/a7/GkeyEnc.java @@ -0,0 +1,44 @@ +package sega.a7; + +import javacard.framework.Util; +import javacard.security.MessageDigest; + +public class GkeyEnc extends AuthCommand { + private static final short RECV_PACKET_SIZE = 63; + private static final byte AUTH_LEVEL = 2; + private static final short PARAM_SIZE = 62; + private static final short IV_INIT_OFFSET = 6; + private static final short DATA_OFFSET = 7; + private static final short DATA_SIZE = 16; + + public GkeyEnc(short cmd, AppData data, MakePacket packet, MessageDigest sha1, + HmacSha1 hmacSha1, Crypt crypt) { + super(cmd, RECV_PACKET_SIZE, PARAM_SIZE, AUTH_LEVEL, data, packet, sha1, hmacSha1, crypt); + } + + public short core(byte[] data, short dataOffset, short dataLength) { + byte ramD_ivInit = data[dataOffset + IV_INIT_OFFSET]; + byte[] ramD_encData = this.m_ee_data.getGeneralBuffer_ramD(); + boolean bInit = false; + if (ramD_encData.length < 48) + return AppConfig.A7_FAIL; + + short ramD_decSize = decData(data, (short) (dataOffset + DATA_OFFSET), DATA_SIZE, ramD_encData, + (short) 0); + if (16 > ramD_decSize) + return AppConfig.A7_FAIL; + + if (1 == ramD_ivInit) + bInit = true; + encUpdate_GKey(ramD_encData, (short) 0, (short) 16, ramD_encData, (short) 16, bInit); + short ramD_encSize = encData(ramD_encData, (short) 16, (short) 16, ramD_encData, (short) 32); + if (16 != ramD_encSize) + return AppConfig.A7_FAIL; + + this.m_ramD_outDataInfo[0] = 32; + this.m_ramD_outDataInfo[1] = 16; + Util.arrayCopyNonAtomic(ramD_encData, this.m_ramD_outDataInfo[0], this.m_ramD_outData, + this.m_ramD_outDataInfo[0], this.m_ramD_outDataInfo[1]); + return AppConfig.A7_SUCCESS; + } +} diff --git a/src/sega/a7/GkeyWrite.java b/src/sega/a7/GkeyWrite.java new file mode 100644 index 0000000..2f12235 --- /dev/null +++ b/src/sega/a7/GkeyWrite.java @@ -0,0 +1,34 @@ +package sega.a7; + +import javacard.security.MessageDigest; + +public class GkeyWrite extends AuthCommand { + private static final short RECV_PACKET_SIZE = 78; + private static final byte AUTH_LEVEL = 2; + private static final short PARAM_SIZE = 46; + + public GkeyWrite(short cmd, AppData data, MakePacket packet, MessageDigest sha1, HmacSha1 hmacSha1, Crypt crypt) { + super(cmd, RECV_PACKET_SIZE, PARAM_SIZE, AUTH_LEVEL, data, packet, sha1, hmacSha1, crypt); + } + + public short core(byte[] data, short dataOffset, short dataLength) { + if (this.m_ee_data.getSflag_ee()) + return AppConfig.A7_EEPWRITE_DISABLE; + + short ramD_dataSize = AppConfig.AES_KEY_SIZE + AppConfig.AES_IV_SIZE; + byte[] ramD_newGKey = this.m_ee_data.getGeneralBuffer_ramD(); + if (ramD_newGKey.length < (short) ramD_dataSize) + return AppConfig.A7_FAIL; + + short ramD_decSize = decData(data, (short) (dataOffset + 6), ramD_dataSize, ramD_newGKey, (short) 0); + + if (ramD_decSize < 32) + return AppConfig.A7_FAIL; + + if (!changeGKey_ee(ramD_newGKey, (short) 0, AppConfig.AES_KEY_SIZE, ramD_newGKey, AppConfig.AES_KEY_SIZE, + AppConfig.AES_IV_SIZE)) + return AppConfig.A7_EEP_WRITEFAIL; + + return AppConfig.A7_SUCCESS; + } +} diff --git a/src/sega/a7/HmacChange.java b/src/sega/a7/HmacChange.java new file mode 100644 index 0000000..912d156 --- /dev/null +++ b/src/sega/a7/HmacChange.java @@ -0,0 +1,28 @@ +package sega.a7; + +import javacard.security.MessageDigest; + +public class HmacChange extends AuthCommand { + private static final short RECV_PACKET_SIZE = 78; + private static final byte AUTH_LEVEL = 2; + private static final short PARAM_SIZE = 46; + + public HmacChange(short cmd, AppData data, MakePacket packet, MessageDigest sha1, + HmacSha1 hmacSha1, Crypt crypt) { + super(cmd, RECV_PACKET_SIZE, PARAM_SIZE, AUTH_LEVEL, data, packet, sha1, hmacSha1, crypt); + } + + public short core(byte[] data, short dataOffset, short dataLength) { + short ramD_dataSize = (short) 32; + byte[] ramD_newHmac = this.m_ee_data.getGeneralBuffer_ramD(); + if (ramD_newHmac.length < ramD_dataSize) + return AppConfig.A7_FAIL; + + short ramD_decSize = decData(data, (short) (dataOffset + 6), ramD_dataSize, ramD_newHmac, (short) 0); + if (20 > ramD_decSize) + return AppConfig.A7_FAIL; + + this.m_ee_data.setKh_ramD(ramD_newHmac, (short) 0, (short) 20); + return AppConfig.A7_SUCCESS; + } +} diff --git a/src/sega/a7/HmacSha1.java b/src/sega/a7/HmacSha1.java new file mode 100644 index 0000000..b6144d5 --- /dev/null +++ b/src/sega/a7/HmacSha1.java @@ -0,0 +1,59 @@ +package sega.a7; + +import javacard.framework.JCSystem; +import javacard.framework.Util; +import javacard.security.MessageDigest; + +public class HmacSha1 { + public static short HMAC_BLOCK_SIZE = 64; + public static short INNER_PAD = 54; + public static short OUTER_PAD = 92; + + private byte[] m_ramD_key = JCSystem.makeTransientByteArray(HMAC_BLOCK_SIZE, (byte) 1); + private byte[] m_ramD_padBuffer = JCSystem.makeTransientByteArray(HMAC_BLOCK_SIZE, (byte) 1); + private MessageDigest m_ee_sha1 = MessageDigest.getInstance((byte) 1, false); + + public boolean update(byte[] inBuff, short inOffset, short inLength) { + if (inBuff == null || inLength <= 0 || inBuff.length < inOffset) + return false; + + this.m_ee_sha1.update(inBuff, inOffset, inLength); + return true; + } + + public boolean sign(byte[] inBuff, short inOffset, short inLength, byte[] sigBuff, short sigOffset) { + if (inBuff == null || inLength <= 0 || sigBuff == null || inOffset + inLength > inBuff.length + || sigOffset + 20 > sigBuff.length) + return false; + + this.m_ee_sha1.doFinal(inBuff, inOffset, inLength, sigBuff, sigOffset); + for (short ii = 0; ii < HMAC_BLOCK_SIZE; ii++) + this.m_ramD_padBuffer[ii] = (byte) (this.m_ramD_key[(short) ii] ^ OUTER_PAD); + this.m_ee_sha1.update(this.m_ramD_padBuffer, (short) 0, (short) this.m_ramD_padBuffer.length); + this.m_ee_sha1.doFinal(sigBuff, sigOffset, (short) 20, sigBuff, sigOffset); + return true; + } + + public boolean init(byte[] key, short offset, short length) { + if (key == null || length <= 0 || key.length < offset + length) + return false; + + if (length > this.m_ramD_key.length) { + this.m_ee_sha1.reset(); + this.m_ee_sha1.doFinal(key, offset, length, this.m_ramD_key, (short) 0); + } else { + Util.arrayCopyNonAtomic(key, offset, this.m_ramD_key, (short) 0, length); + } + + if (length < this.m_ramD_key.length) { + Util.arrayFillNonAtomic(this.m_ramD_key, length, (short) (this.m_ramD_key.length - length), (byte) 0); + } + + this.m_ee_sha1.reset(); + for (short ii = 0; ii < HMAC_BLOCK_SIZE; ii++) { + this.m_ramD_padBuffer[ii] = (byte) (this.m_ramD_key[ii] ^ INNER_PAD); + } + this.m_ee_sha1.init(this.m_ramD_padBuffer, (short) 0, (short) this.m_ramD_padBuffer.length); + return true; + } +} diff --git a/src/sega/a7/KeyChange.java b/src/sega/a7/KeyChange.java new file mode 100644 index 0000000..a7991e6 --- /dev/null +++ b/src/sega/a7/KeyChange.java @@ -0,0 +1,28 @@ +package sega.a7; + +import javacard.security.MessageDigest; + +public class KeyChange extends AuthCommand { + private static final short RECV_PACKET_SIZE = 78; + private static final byte AUTH_LEVEL = 2; + private static final short PARAM_SIZE = 46; + + public KeyChange(short cmd, AppData data, MakePacket packet, MessageDigest sha1, + HmacSha1 hmacSha1, Crypt crypt) { + super(cmd, RECV_PACKET_SIZE, PARAM_SIZE, AUTH_LEVEL, data, packet, sha1, hmacSha1, crypt); + } + + public short core(byte[] data, short dataOffset, short dataLength) { + short ramD_dataSize = (short) 32; + byte[] ramD_newKey = this.m_ee_data.getGeneralBuffer_ramD(); + if (ramD_newKey.length < ramD_dataSize) + return AppConfig.A7_FAIL; + + short ramD_decSize = decData(data, (short) (dataOffset + 6), ramD_dataSize, ramD_newKey, (short) 0); + if (32 > (short) ramD_decSize) + return AppConfig.A7_FAIL; + + boolean bRet = changeConnectionKey_ee(ramD_newKey, (short) 0, (short) 16, ramD_newKey, (short) 16, (short) 16); + return (short) (bRet ? 0 : 11); + } +} diff --git a/src/sega/a7/KeychipInfoRead.java b/src/sega/a7/KeychipInfoRead.java new file mode 100644 index 0000000..e82f0b1 --- /dev/null +++ b/src/sega/a7/KeychipInfoRead.java @@ -0,0 +1,34 @@ +package sega.a7; + +import javacard.framework.Util; +import javacard.security.MessageDigest; + +public class KeychipInfoRead extends AuthCommand { + private static final short RECV_PACKET_SIZE = 46; + private static final byte AUTH_LEVEL = 2; + private static final short PARAM_SIZE = 142; + + public KeychipInfoRead(short cmd, AppData data, MakePacket packet, MessageDigest sha1, HmacSha1 hmacSha1, + Crypt crypt) { + super(cmd, RECV_PACKET_SIZE, PARAM_SIZE, AUTH_LEVEL, data, packet, sha1, hmacSha1, crypt); + } + + public short core(byte[] dta, short dataOffset, short dataLength) { + byte[] ee_keychipInfo = this.m_ee_data.getKeychipInfo_ee(); + byte[] ramD_encKeychipInfo = this.m_ee_data.getGeneralBuffer_ramD(); + if (ramD_encKeychipInfo.length < ee_keychipInfo.length) + return AppConfig.A7_FAIL; + + short encSize = encData(ee_keychipInfo, (short) 0, (short) ee_keychipInfo.length, ramD_encKeychipInfo, + (short) 0); + if (ee_keychipInfo.length > encSize) + return AppConfig.A7_FAIL; + + this.m_ramD_outDataInfo[0] = 0; + this.m_ramD_outDataInfo[1] = encSize; + Util.arrayCopyNonAtomic(ramD_encKeychipInfo, this.m_ramD_outDataInfo[0], this.m_ramD_outData, + this.m_ramD_outDataInfo[0], this.m_ramD_outDataInfo[1]); + + return AppConfig.A7_SUCCESS; + } +} diff --git a/src/sega/a7/KeychipInfoWrite.java b/src/sega/a7/KeychipInfoWrite.java new file mode 100644 index 0000000..fee917f --- /dev/null +++ b/src/sega/a7/KeychipInfoWrite.java @@ -0,0 +1,33 @@ +package sega.a7; + +import javacard.security.MessageDigest; + +public class KeychipInfoWrite extends AuthCommand { + private static final short RECV_PACKET_SIZE = 142; + private static final byte AUTH_LEVEL = 2; + private static final short PARAM_SIZE = 46; + + public KeychipInfoWrite(short cmd, AppData data, MakePacket packet, MessageDigest sha1, HmacSha1 hmacSha1, + Crypt crypt) { + super(cmd, RECV_PACKET_SIZE, PARAM_SIZE, AUTH_LEVEL, data, packet, sha1, hmacSha1, crypt); + } + + public short core(byte[] data, short dataOffset, short dataLength) { + if (this.m_ee_data.getSflag_ee()) + return AppConfig.A7_EEPWRITE_DISABLE; + + short ramD_dataSize = AppConfig.KEYCHIP_INFO_SIZE; + byte[] ramD_newKeychipInfo = this.m_ee_data.getGeneralBuffer_ramD(); + if (ramD_newKeychipInfo.length < ramD_dataSize) + return AppConfig.A7_FAIL; + + short ramD_decSize = decData(data, (short) (AppConfig.HEADER_SIZE + dataOffset), ramD_dataSize, ramD_newKeychipInfo, + (short) 0); + if (ramD_dataSize > ramD_decSize) + return AppConfig.A7_FAIL; + + if (!this.m_ee_data.setKeychipInfo_ee(ramD_newKeychipInfo, (short) 0, ramD_decSize)) + return AppConfig.A7_EEP_WRITEFAIL; + return AppConfig.A7_SUCCESS; + } +} diff --git a/src/sega/a7/LvEnable.java b/src/sega/a7/LvEnable.java new file mode 100644 index 0000000..1fd3491 --- /dev/null +++ b/src/sega/a7/LvEnable.java @@ -0,0 +1,25 @@ +package sega.a7; + +import javacard.security.MessageDigest; + +public class LvEnable extends Command { + private static final short RECV_PACKET_SIZE = 26; + private static final byte AUTH_LEVEL = -1; + private static final short PARAM_SIZE = 26; + private static final byte SET_AUTH_LEVEL = 0; + + public LvEnable(short cmd, AppData data, MakePacket packet, MessageDigest sha1) { + super(cmd, RECV_PACKET_SIZE, PARAM_SIZE, data, packet, sha1); + } + + public short core(byte[] data, short dataOffset, short dataLength) { + if (this.m_ee_data.getLevel_ramD() != AUTH_LEVEL) + return AppConfig.A7_LV_ERROR; + + if (this.m_ee_data.getSflag_ee()) + return AppConfig.A7_EEPWRITE_DISABLE; + + this.m_ee_data.setLevel_ramD(SET_AUTH_LEVEL); + return AppConfig.A7_SUCCESS; + } +} diff --git a/src/sega/a7/LvGet.java b/src/sega/a7/LvGet.java new file mode 100644 index 0000000..3a0f931 --- /dev/null +++ b/src/sega/a7/LvGet.java @@ -0,0 +1,25 @@ +package sega.a7; + +import javacard.framework.Util; +import javacard.security.MessageDigest; + +public class LvGet extends Command { + private static final short RECV_PACKET_SIZE = 26; + private static final short PARAM_SIZE = 27; + + public LvGet(short cmd, AppData data, MakePacket packet, MessageDigest sha1) { + super(cmd, RECV_PACKET_SIZE, PARAM_SIZE, data, packet, sha1); + } + + public short core(byte[] data, short dataOffset, short dataLength) { + byte[] ramD_level = this.m_ee_data.getGeneralBuffer_ramD(); + ramD_level[0] = this.m_ee_data.getLevel_ramD(); + + this.m_ramD_outDataInfo[0] = 0; + this.m_ramD_outDataInfo[1] = 1; + Util.arrayCopyNonAtomic(ramD_level, this.m_ramD_outDataInfo[0], this.m_ramD_outData, this.m_ramD_outDataInfo[0], + this.m_ramD_outDataInfo[1]); + + return AppConfig.A7_SUCCESS; + } +} diff --git a/src/sega/a7/MakePacket.java b/src/sega/a7/MakePacket.java new file mode 100644 index 0000000..36cdcbb --- /dev/null +++ b/src/sega/a7/MakePacket.java @@ -0,0 +1,60 @@ +package sega.a7; + +import javacard.framework.JCSystem; +import javacard.framework.Util; +import javacard.security.MessageDigest; + +public class MakePacket { + private byte[] m_ramD_buffer = JCSystem.makeTransientByteArray((short) 20, (byte) 1); + + public boolean setData(byte[] kh, short khOffset, short khLength, short tag, + short paramSize, short result, short cmd, byte[] data, short dataOffset, + short dataLength, byte[] nonceEvent, short eventOffset, short eventLength, byte[] nonceOdd, + short oddOffset, short oddLength, byte[] packet, short packetOffset, short packetLength, + MessageDigest sha1, HmacSha1 hmacSha1) { + short ramD_offset = packetOffset; + + if (packet == null || packetLength < paramSize) + return false; + + if (tag != AppConfig.A7_TAG_RSP_COMMAND) { + if (tag == AppConfig.A7_TAG_RSP_AUTH_COMMAND || tag == AppConfig.A7_TAG_RSP_RSA_COMMAND) { + if (nonceEvent == null || nonceOdd == null || hmacSha1 == null) + return false; + } else { + return false; + } + } + + sha1.reset(); + Util.setShort(packet, ramD_offset, tag); + ramD_offset = (short) (ramD_offset + 2); + Util.setShort(packet, ramD_offset, paramSize); + ramD_offset = (short) (ramD_offset + 2); + Util.setShort(packet, ramD_offset, result); + ramD_offset = (short) (ramD_offset + 2); + Util.setShort(this.m_ramD_buffer, (short) 0, cmd); + if (data == null) { + sha1.update(packet, packetOffset, (short) (ramD_offset - packetOffset)); + sha1.doFinal(this.m_ramD_buffer, (short) 0, (short) 2, packet, ramD_offset); + } else { + sha1.update(packet, packetOffset, (short) (ramD_offset - packetOffset)); + sha1.update(this.m_ramD_buffer, (short) 0, (short) 2); + Util.arrayCopyNonAtomic(data, dataOffset, packet, ramD_offset, dataLength); + ramD_offset = (short) (ramD_offset + dataLength); + sha1.doFinal(data, dataOffset, dataLength, packet, ramD_offset); + } + + if (tag == AppConfig.A7_TAG_RSP_COMMAND) + return true; + + Util.arrayCopyNonAtomic(packet, (short) ramD_offset, this.m_ramD_buffer, (short) 0, (short) 20); + Util.arrayCopyNonAtomic(nonceEvent, (short) eventOffset, packet, (short) ramD_offset, (short) eventLength); + ramD_offset = (short) ((short) ramD_offset + (short) eventLength); + hmacSha1.init(kh, (short) khOffset, (short) khLength); + hmacSha1.update(this.m_ramD_buffer, (short) 0, (short) 20); + hmacSha1.update(nonceEvent, (short) eventOffset, (short) eventLength); + hmacSha1.sign(nonceOdd, (short) oddOffset, (short) oddLength, packet, (short) ramD_offset); + return true; + } +} diff --git a/src/sega/a7/NoCommand.java b/src/sega/a7/NoCommand.java new file mode 100644 index 0000000..05913b2 --- /dev/null +++ b/src/sega/a7/NoCommand.java @@ -0,0 +1,23 @@ +package sega.a7; + +import javacard.security.MessageDigest; + +public class NoCommand extends Command { + public NoCommand(short cmd, AppData data, MakePacket packet, MessageDigest sha1) { + super(cmd, (short) 0, (short) 26, data, packet, sha1); + } + + public short execute(byte[] data, short cmd, short dataLength, byte[] dst, short dstOffset, short dstLength) { + return (6 > dataLength) ? makeNoCommandErrorPacket((short) 4, cmd, dst, dstOffset, dstLength) + : makeNoCommandErrorPacket((short) 7, cmd, dst, dstOffset, dstLength); + } + + private short makeNoCommandErrorPacket(short error, short cmd, byte[] sendPacket, short packetOffset, + short packetLength) { + this.m_ee_data.setLastError_ramD(error); + this.m_ee_packet.setData(null, (short) 0, (short) 0, AppConfig.A7_TAG_RSP_COMMAND, (short) 26, error, + cmd, null, (short) 0, (short) 0, null, (short) 0, (short) 0, null, (short) 0, (short) 0, + sendPacket, packetOffset, packetLength, this.m_ee_sha1, null); + return 26; + } +} diff --git a/src/sega/a7/PlayCountIncrement.java b/src/sega/a7/PlayCountIncrement.java new file mode 100644 index 0000000..be15ac4 --- /dev/null +++ b/src/sega/a7/PlayCountIncrement.java @@ -0,0 +1,27 @@ +package sega.a7; + +import javacard.security.MessageDigest; + +public class PlayCountIncrement extends AuthCommand { + private static final short RECV_PACKET_SIZE = 47; + private static final byte AUTH_LEVEL = 2; + private static final short PARAM_SIZE = 46; + + public PlayCountIncrement(short cmd, AppData data, MakePacket packet, MessageDigest sha1, HmacSha1 hmacSha1, + Crypt crypt) { + super(cmd, RECV_PACKET_SIZE, PARAM_SIZE, AUTH_LEVEL, data, packet, sha1, hmacSha1, crypt); + } + + public short core(byte[] data, short dataOffset, short dataLength) { + byte[] arrayOfByte = this.m_ee_data.getGeneralBuffer_ramD(); + if (arrayOfByte.length < 1) + return AppConfig.A7_FAIL; + + if (dataLength < (short) (6 + dataOffset + 1)) + return AppConfig.A7_BAD_DATASIZE; + + arrayOfByte[0] = data[(short) (6 + dataOffset)]; + this.m_ee_data.addValuePlayCounter_ee(arrayOfByte[0]); + return AppConfig.A7_SUCCESS; + } +} diff --git a/src/sega/a7/PlayCountRead.java b/src/sega/a7/PlayCountRead.java new file mode 100644 index 0000000..909b1d1 --- /dev/null +++ b/src/sega/a7/PlayCountRead.java @@ -0,0 +1,40 @@ +package sega.a7; + +import javacard.framework.Util; +import javacard.security.MessageDigest; +import javacard.security.RandomData; + +public class PlayCountRead extends AuthCommand { + private static final short RECV_PACKET_SIZE = 46; + private static final byte AUTH_LEVEL = 2; + private static final short PARAM_SIZE = 62; + private static final short PLAY_COUNT_VALUE_SIZE = 4; + private static final short RANDOM_VALUE_SIZE = 12; + private static final short ENC_DATA_SIZE = 16; + private RandomData m_ee_rand; + + public PlayCountRead(short cmd, AppData data, MakePacket packet, MessageDigest sha1, + HmacSha1 hmacSha1, Crypt crypt, RandomData rand) { + super(cmd, RECV_PACKET_SIZE, PARAM_SIZE, AUTH_LEVEL, data, packet, sha1, hmacSha1, crypt); + this.m_ee_rand = rand; + } + + public short core(byte[] data, short dataOffset, short dataLength) { + byte[] ramD_playCount = this.m_ee_data.getGeneralBuffer_ramD(); + if (ramD_playCount.length < PLAY_COUNT_VALUE_SIZE + RANDOM_VALUE_SIZE + ENC_DATA_SIZE) + return AppConfig.A7_FAIL; + this.m_ee_rand.generateData(ramD_playCount, (short) 0, (short) (PLAY_COUNT_VALUE_SIZE + RANDOM_VALUE_SIZE)); + this.m_ee_data.getPlayCounter_ee(ramD_playCount, (short) 0, PLAY_COUNT_VALUE_SIZE); + short ramD_encSize = encData(ramD_playCount, (short) 0, ENC_DATA_SIZE, ramD_playCount, + (short) (PLAY_COUNT_VALUE_SIZE + RANDOM_VALUE_SIZE)); + if (ramD_encSize != ENC_DATA_SIZE) + return AppConfig.A7_FAIL; + + this.m_ramD_outDataInfo[AppConfig.SEND_BUUFER_INFO_OFFSET] = 16; + this.m_ramD_outDataInfo[AppConfig.SEND_BUUFER_INFO_SIZE] = ramD_encSize; + Util.arrayCopyNonAtomic(ramD_playCount, this.m_ramD_outDataInfo[AppConfig.SEND_BUUFER_INFO_OFFSET], + this.m_ramD_outData, this.m_ramD_outDataInfo[AppConfig.SEND_BUUFER_INFO_OFFSET], + this.m_ramD_outDataInfo[AppConfig.SEND_BUUFER_INFO_SIZE]); + return AppConfig.A7_SUCCESS; + } +} diff --git a/src/sega/a7/PrikeyExponentWrite.java b/src/sega/a7/PrikeyExponentWrite.java new file mode 100644 index 0000000..2ec98b4 --- /dev/null +++ b/src/sega/a7/PrikeyExponentWrite.java @@ -0,0 +1,41 @@ +package sega.a7; + +import javacard.security.MessageDigest; + +public class PrikeyExponentWrite extends AuthCommand { + private static final short RECV_PACKET_SIZE = 302; + private static final byte AUTH_LEVEL = 2; + private static final short PARAM_SIZE = 46; + + public PrikeyExponentWrite(short cmd, AppData data, MakePacket packet, MessageDigest sha1, HmacSha1 hmacSha1, + Crypt crypt) { + super(cmd, RECV_PACKET_SIZE, PARAM_SIZE, AUTH_LEVEL, data, packet, sha1, hmacSha1, crypt); + } + + public short core(byte[] data, short dataOffset, short dataLength) { + if (this.m_ee_data.getSflag_ee()) + return AppConfig.A7_EEPWRITE_DISABLE; + + short ramD_dataSize = (short) 256; + byte[] ramD_newRSAKey = this.m_ee_data.getGeneralBuffer_ramD(); + if (ramD_newRSAKey.length < (short) ramD_dataSize) + return AppConfig.A7_FAIL; + + short ramD_decSize = decData(data, (short) (6 + dataOffset), ramD_dataSize, ramD_newRSAKey, (short) 0); + if (ramD_dataSize > ramD_decSize) + return AppConfig.A7_FAIL; + if (!this.m_ee_data.setRsaPriKeyExponent_ee(ramD_newRSAKey, (short) 0, (short) 256)) + return AppConfig.A7_EEP_WRITEFAIL; + + this.m_ee_data.activeRssaExponentUpdate_ramD(); + if (this.m_ee_data.getRsaModulusUpdate_ramD()) { + byte[] exponent = this.m_ee_data.getRsaPriExponent_ee(); + byte[] modulus = this.m_ee_data.getRsaPriModulus_ee(); + if (!changeRsaKey_ee(modulus, (short) 0, (short) modulus.length, exponent, (short) 0, + (short) exponent.length)) + return AppConfig.A7_FAIL; + } + + return AppConfig.A7_SUCCESS; + } +} diff --git a/src/sega/a7/PrivkeyModulusWrite.java b/src/sega/a7/PrivkeyModulusWrite.java new file mode 100644 index 0000000..4000da8 --- /dev/null +++ b/src/sega/a7/PrivkeyModulusWrite.java @@ -0,0 +1,42 @@ +package sega.a7; + +import javacard.security.MessageDigest; + +public class PrivkeyModulusWrite extends AuthCommand { + private static final short RECV_PACKET_SIZE = 302; + private static final byte AUTH_LEVEL = 2; + private static final short PARAM_SIZE = 46; + + public PrivkeyModulusWrite(short cmd, AppData data, MakePacket packet, MessageDigest sha1, HmacSha1 hmacSha1, + Crypt crypt) { + super(cmd, RECV_PACKET_SIZE, PARAM_SIZE, AUTH_LEVEL, data, packet, sha1, hmacSha1, crypt); + } + + public short core(byte[] data, short dataOffset, short dataLength) { + if (this.m_ee_data.getSflag_ee()) + return AppConfig.A7_EEPWRITE_DISABLE; + + short ramD_dataSize = (short) 256; + byte[] ramD_newRSAKey = this.m_ee_data.getGeneralBuffer_ramD(); + if (ramD_newRSAKey.length < ramD_dataSize) + return AppConfig.A7_FAIL; + + short ramD_decSize = decData(data, (short) (6 + dataOffset), ramD_dataSize, ramD_newRSAKey, (short) 0); + if (ramD_dataSize > ramD_decSize) + return AppConfig.A7_FAIL; + + if (!this.m_ee_data.setRsaPriKeyModulus_ee(ramD_newRSAKey, (short) 0, (short) 256)) + return AppConfig.A7_EEP_WRITEFAIL; + + this.m_ee_data.activeRssaModulusUpdate_ramD(); + if (this.m_ee_data.getRsaExponentUpdate_ramD()) { + byte[] exponent = this.m_ee_data.getRsaPriExponent_ee(); + byte[] modulus = this.m_ee_data.getRsaPriModulus_ee(); + if (!changeRsaKey_ee(modulus, (short) 0, (short) modulus.length, exponent, (short) 0, + (short) exponent.length)) + return AppConfig.A7_FAIL; + } + + return AppConfig.A7_SUCCESS; + } +} diff --git a/src/sega/a7/RanGet.java b/src/sega/a7/RanGet.java new file mode 100644 index 0000000..5bce2ff --- /dev/null +++ b/src/sega/a7/RanGet.java @@ -0,0 +1,37 @@ +package sega.a7; + +import javacard.framework.Util; +import javacard.security.MessageDigest; +import javacard.security.RandomData; + +public class RanGet extends AuthCommand { + private static final short RECV_PACKET_SIZE = 46; + private static final byte AUTH_LEVEL = 2; + private static final short PARAM_SIZE = 62; + private static final short RAN_SIZE = 16; + + private RandomData m_ee_rand; + + public RanGet(short cmd, AppData data, MakePacket packet, MessageDigest sha1, HmacSha1 hmacSha1, Crypt crypt, + RandomData rand) { + super(cmd, RECV_PACKET_SIZE, PARAM_SIZE, AUTH_LEVEL, data, packet, sha1, hmacSha1, crypt); + this.m_ee_rand = rand; + } + + public short core(byte[] data, short dataOffset, short dataLength) { + byte[] ramD_ranData = this.m_ee_data.getGeneralBuffer_ramD(); + if (ramD_ranData.length < 32) + return AppConfig.A7_FAIL; + + this.m_ee_rand.generateData(ramD_ranData, (short) 0, RAN_SIZE); + short ramD_encSize = encData(ramD_ranData, (short) 0, RAN_SIZE, ramD_ranData, RAN_SIZE); + if (ramD_encSize != 16) + return AppConfig.A7_FAIL; + + this.m_ramD_outDataInfo[0] = RAN_SIZE; + this.m_ramD_outDataInfo[1] = ramD_encSize; + Util.arrayCopyNonAtomic(ramD_ranData, this.m_ramD_outDataInfo[0], this.m_ramD_outData, + this.m_ramD_outDataInfo[0], this.m_ramD_outDataInfo[1]); + return AppConfig.A7_SUCCESS; + } +} diff --git a/src/sega/a7/SessionClose.java b/src/sega/a7/SessionClose.java new file mode 100644 index 0000000..886d3ee --- /dev/null +++ b/src/sega/a7/SessionClose.java @@ -0,0 +1,17 @@ +package sega.a7; + +import javacard.security.MessageDigest; + +public class SessionClose extends Command { + private static final short RECV_PACKET_SIZE = 26; + private static final short PARAM_SIZE = 26; + + public SessionClose(short cmd, AppData data, MakePacket packet, MessageDigest sha1) { + super(cmd, RECV_PACKET_SIZE, PARAM_SIZE, data, packet, sha1); + } + + public short core(byte[] data, short dataOffset, short dataLength) { + this.m_ee_data.setSession_ramD(AppData.SESSION_DISABLE); + return AppConfig.A7_SUCCESS; + } +} diff --git a/src/sega/a7/SessionOpen.java b/src/sega/a7/SessionOpen.java new file mode 100644 index 0000000..6b25621 --- /dev/null +++ b/src/sega/a7/SessionOpen.java @@ -0,0 +1,25 @@ +package sega.a7; + +import javacard.framework.Util; +import javacard.security.MessageDigest; + +public class SessionOpen extends Command { + private static final short RECV_PACKET_SIZE = 26; + private static final short PARAM_SIZE = 46; + + public SessionOpen(short cmd, AppData data, MakePacket packet, MessageDigest sha1) { + super(cmd, RECV_PACKET_SIZE, PARAM_SIZE, data, packet, sha1); + } + + public short core(byte[] data, short dataOffset, short dataLength) { + byte[] ramD_nonceEvent = this.m_ee_data.getNewNonceEvent_ramD(); + this.m_ee_data.setLastNonceEvent_ramD(ramD_nonceEvent, (short) 0, (short) ramD_nonceEvent.length); + this.m_ee_data.setSession_ramD(AppData.SESSION_ENABLE); + this.m_ramD_outDataInfo[0] = 0; + this.m_ramD_outDataInfo[1] = (byte) ramD_nonceEvent.length; + Util.arrayCopyNonAtomic(ramD_nonceEvent, this.m_ramD_outDataInfo[0], this.m_ramD_outData, + this.m_ramD_outDataInfo[0], this.m_ramD_outDataInfo[1]); + + return AppConfig.A7_SUCCESS; + } +} diff --git a/src/sega/a7/SflagWrite.java b/src/sega/a7/SflagWrite.java new file mode 100644 index 0000000..eb41d8c --- /dev/null +++ b/src/sega/a7/SflagWrite.java @@ -0,0 +1,21 @@ +package sega.a7; + +import javacard.security.MessageDigest; + +public class SflagWrite extends AuthCommand { + private static final short RECV_PACKET_SIZE = 46; + private static final byte AUTH_LEVEL = 2; + private static final short PARAM_SIZE = 46; + + public SflagWrite(short cmd, AppData data, MakePacket packet, MessageDigest sha1, HmacSha1 hmacSha1, Crypt crypt) { + super(cmd, RECV_PACKET_SIZE, PARAM_SIZE, AUTH_LEVEL, data, packet, sha1, hmacSha1, crypt); + } + + public short core(byte[] data, short dataOffset, short dataLength) { + if (this.m_ee_data.getSflag_ee()) + return AppConfig.A7_EEPWRITE_DISABLE; + + this.m_ee_data.activeSflag(); + return AppConfig.A7_SUCCESS; + } +} diff --git a/src/sega/a7/StorageRead.java b/src/sega/a7/StorageRead.java new file mode 100644 index 0000000..4b5b239 --- /dev/null +++ b/src/sega/a7/StorageRead.java @@ -0,0 +1,38 @@ +package sega.a7; + +import javacard.framework.Util; +import javacard.security.MessageDigest; + +public class StorageRead extends AuthCommand { + private static final short RECV_PACKET_SIZE = 50; + private static final byte AUTH_LEVEL = 2; + private static final short PARAM_SIZE = 46; + private static final short READ_OFFSET_OFFSET = 6; + private static final short DATA_SIZE_OFFSET = 8; + + public StorageRead(short cmd, AppData data, MakePacket packet, MessageDigest sha1, HmacSha1 hmacSha1, Crypt crypt) { + super(cmd, RECV_PACKET_SIZE, PARAM_SIZE, AUTH_LEVEL, data, packet, sha1, hmacSha1, crypt); + } + + public short core(byte[] data, short dataOffset, short dataLength) { + short ramD_readSize = Util.getShort(data, (short) (dataOffset + DATA_SIZE_OFFSET)); + if ((ramD_readSize % 16) != 0) + ramD_readSize = (short) (ramD_readSize + (short) (16 - (short) (ramD_readSize % 16))); + short ramD_bufferOffset = (short) Util.getShort(data, (short) (dataOffset + READ_OFFSET_OFFSET)); + byte[] ee_storageData = this.m_ee_data.getStorageData_ee(); + byte[] ramD_encStorageData = this.m_ee_data.getGeneralBuffer_ramD(); + if (ramD_encStorageData.length < ramD_readSize || 192 < ramD_readSize || ramD_readSize == 0 + || AppConfig.STORAGE_SIZE < (short) (ramD_readSize + ramD_bufferOffset)) + return AppConfig.A7_BAD_PARAMETER; + short ramD_encSize = encData(ee_storageData, ramD_bufferOffset, ramD_readSize, ramD_encStorageData, (short) 0); + if (ramD_readSize > ramD_encSize) + return AppConfig.A7_FAIL; + + this.m_ramD_outDataInfo[0] = 0; + this.m_ramD_outDataInfo[1] = ramD_encSize; + Util.arrayCopyNonAtomic(ramD_encStorageData, this.m_ramD_outDataInfo[0], this.m_ramD_outData, + this.m_ramD_outDataInfo[0], this.m_ramD_outDataInfo[1]); + setSendPacketSize_ramD((short) (46 + ramD_readSize)); + return AppConfig.A7_SUCCESS; + } +} diff --git a/src/sega/a7/StorageSizeGet.java b/src/sega/a7/StorageSizeGet.java new file mode 100644 index 0000000..64f5baa --- /dev/null +++ b/src/sega/a7/StorageSizeGet.java @@ -0,0 +1,41 @@ +package sega.a7; + +import javacard.framework.Util; +import javacard.security.MessageDigest; +import javacard.security.RandomData; + +public class StorageSizeGet extends AuthCommand { + private static final short RECV_PACKET_SIZE = 46; + private static final byte AUTH_LEVEL = 2; + private static final short PARAM_SIZE = 62; + private static final short STORAGE_SIZE_VALUE_SIZE = 2; + private static final short RANDOM_VALUE_SIZE = 14; + private static final short ENC_DATA_SIZE = 16; + private RandomData m_ee_rand; + + public StorageSizeGet(short cmd, AppData data, MakePacket packet, MessageDigest sha1, HmacSha1 hmacSha1, + Crypt crypt, + RandomData rand) { + super(cmd, RECV_PACKET_SIZE, PARAM_SIZE, AUTH_LEVEL, data, packet, sha1, hmacSha1, crypt); + this.m_ee_rand = rand; + } + + public short core(byte[] data, short dataOffset, short dataLength) { + byte[] ramD_storageSize = this.m_ee_data.getGeneralBuffer_ramD(); + if (ramD_storageSize.length < (short) (STORAGE_SIZE_VALUE_SIZE + RANDOM_VALUE_SIZE + ENC_DATA_SIZE)) + return AppConfig.A7_FAIL; + + this.m_ee_rand.generateData(ramD_storageSize, (short) 0, (short) (STORAGE_SIZE_VALUE_SIZE + RANDOM_VALUE_SIZE)); + Util.setShort(ramD_storageSize, (short) 0, AppConfig.STORAGE_SIZE); + short ramD_encSize = encData(ramD_storageSize, (short) 0, ENC_DATA_SIZE, ramD_storageSize, + (short) (STORAGE_SIZE_VALUE_SIZE + RANDOM_VALUE_SIZE)); + if (ramD_encSize != ENC_DATA_SIZE) + return AppConfig.A7_FAIL; + + this.m_ramD_outDataInfo[0] = (short) (STORAGE_SIZE_VALUE_SIZE + RANDOM_VALUE_SIZE); + this.m_ramD_outDataInfo[1] = ramD_encSize; + Util.arrayCopyNonAtomic(ramD_storageSize, this.m_ramD_outDataInfo[0], this.m_ramD_outData, + this.m_ramD_outDataInfo[0], this.m_ramD_outDataInfo[1]); + return AppConfig.A7_SUCCESS; + } +} diff --git a/src/sega/a7/StorageWrite.java b/src/sega/a7/StorageWrite.java new file mode 100644 index 0000000..ae9e68a --- /dev/null +++ b/src/sega/a7/StorageWrite.java @@ -0,0 +1,41 @@ +package sega.a7; + +import javacard.framework.Util; +import javacard.security.MessageDigest; + +public class StorageWrite extends AuthCommand { + private static final short RECV_PACKET_SIZE = 0; + private static final byte AUTH_LEVEL = 2; + private static final short PARAM_SIZE = 46; + private static final short RECV_PACKET_EXCLUDING_DATA_SIZE = 50; + private static final short DATA_SIZE_OFFSET = 6; + private static final short WRITE_OFFSET_OFFSET = 8; + private static final short WRITE_DATA_OFFSET = 10; + + public StorageWrite(short cmd, AppData data, MakePacket packet, MessageDigest sha1, HmacSha1 hmacSha1, + Crypt crypt) { + super(cmd, RECV_PACKET_SIZE, PARAM_SIZE, AUTH_LEVEL, data, packet, sha1, hmacSha1, crypt); + } + + public short core(byte[] data, short dataOffset, short dataLength) { + short ramD_paramsize = Util.getShort(data, (short) (dataOffset + 2)); + short ramD_encDataSize = (short) (ramD_paramsize - RECV_PACKET_EXCLUDING_DATA_SIZE); + short ramD_wirteDataSize = Util.getShort(data, (short) (dataOffset + DATA_SIZE_OFFSET)); + short ramD_bufferOffset = Util.getShort(data, (short) (dataOffset + WRITE_OFFSET_OFFSET)); + byte[] ramD_newWriteData = this.m_ee_data.getGeneralBuffer_ramD(); + + if ((ramD_encDataSize % 16) != 0 || ramD_newWriteData.length < ramD_encDataSize + || ramD_wirteDataSize == 0 + || ramD_wirteDataSize + ramD_bufferOffset > AppConfig.STORAGE_SIZE) + return AppConfig.A7_BAD_PARAMETER; + + short ramD_decSize = decData(data, (short) (dataOffset + WRITE_DATA_OFFSET), ramD_encDataSize, + ramD_newWriteData, (short) 0); + if (ramD_wirteDataSize > ramD_decSize) + return AppConfig.A7_FAIL; + + if (!this.m_ee_data.setStorageData_ee(ramD_newWriteData, (short) 0, ramD_wirteDataSize, ramD_bufferOffset)) + return AppConfig.A7_EEP_WRITEFAIL; + return AppConfig.A7_SUCCESS; + } +} diff --git a/src/sega/a7/TraceDataInfoRead.java b/src/sega/a7/TraceDataInfoRead.java new file mode 100644 index 0000000..25b01fe --- /dev/null +++ b/src/sega/a7/TraceDataInfoRead.java @@ -0,0 +1,33 @@ +package sega.a7; + +import javacard.framework.Util; +import javacard.security.MessageDigest; + +public class TraceDataInfoRead extends AuthCommand { + private static final short RECV_PACKET_SIZE = 46; + private static final byte AUTH_LEVEL = 2; + private static final short PARAM_SIZE = 62; + + public TraceDataInfoRead(short cmd, AppData data, MakePacket packet, MessageDigest sha1, HmacSha1 hmacSha1, + Crypt crypt) { + super(cmd, RECV_PACKET_SIZE, PARAM_SIZE, AUTH_LEVEL, data, packet, sha1, hmacSha1, crypt); + } + + public short core(byte[] data, short dataOffset, short dataLength) { + byte[] ee_traceDataInfo = this.m_ee_data.getTraceDataInfo_ee(); + byte[] ramD_encTraceDataInfo = this.m_ee_data.getGeneralBuffer_ramD(); + if (ramD_encTraceDataInfo.length < ee_traceDataInfo.length) + return AppConfig.A7_FAIL; + + short ramD_encSize = encData(ee_traceDataInfo, (short) 0, (short) ee_traceDataInfo.length, + ramD_encTraceDataInfo, (short) 0); + if (ee_traceDataInfo.length > (short) ramD_encSize) + return AppConfig.A7_FAIL; + + this.m_ramD_outDataInfo[0] = 0; + this.m_ramD_outDataInfo[1] = ramD_encSize; + Util.arrayCopyNonAtomic(ramD_encTraceDataInfo, this.m_ramD_outDataInfo[0], this.m_ramD_outData, + this.m_ramD_outDataInfo[0], this.m_ramD_outDataInfo[1]); + return AppConfig.A7_SUCCESS; + } +} diff --git a/src/sega/a7/TraceDataInfoWrite.java b/src/sega/a7/TraceDataInfoWrite.java new file mode 100644 index 0000000..231e3a0 --- /dev/null +++ b/src/sega/a7/TraceDataInfoWrite.java @@ -0,0 +1,30 @@ +package sega.a7; + +import javacard.security.MessageDigest; + +public class TraceDataInfoWrite extends AuthCommand { + private static final short RECV_PACKET_SIZE = 62; + private static final byte AUTH_LEVEL = 2; + private static final short PARAM_SIZE = 46; + + public TraceDataInfoWrite(short cmd, AppData data, MakePacket packet, MessageDigest sha1, HmacSha1 hmacSha1, + Crypt crypt) { + super(cmd, RECV_PACKET_SIZE, PARAM_SIZE, AUTH_LEVEL, data, packet, sha1, hmacSha1, crypt); + } + + public short core(byte[] data, short dataOffset, short dataLength) { + short ramD_dataSize = 16; + byte[] ramD_newTraceDataInfo = this.m_ee_data.getGeneralBuffer_ramD(); + if (ramD_newTraceDataInfo.length < ramD_dataSize) + return AppConfig.A7_FAIL; + + short ramD_decSize = decData(data, (short) (dataOffset + 6), ramD_dataSize, ramD_newTraceDataInfo, (short) 0); + + if (ramD_decSize < ramD_dataSize) + return AppConfig.A7_FAIL; + + if (!this.m_ee_data.setTraceDataInfo_ee(ramD_newTraceDataInfo, (short) 0, ramD_decSize)) + return AppConfig.A7_EEP_WRITEFAIL; + return AppConfig.A7_SUCCESS; + } +} diff --git a/src/sega/a7/UdataRead.java b/src/sega/a7/UdataRead.java new file mode 100644 index 0000000..8e8503d --- /dev/null +++ b/src/sega/a7/UdataRead.java @@ -0,0 +1,33 @@ +package sega.a7; + +import javacard.framework.Util; +import javacard.security.MessageDigest; + +public class UdataRead extends AuthCommand { + private static final short RECV_PACKET_SIZE = 46; + private static final byte AUTH_LEVEL = 2; + private static final short PARAM_SIZE = 62; + + public UdataRead(short cmd, AppData data, MakePacket packet, MessageDigest sha1, HmacSha1 hmacSha1, Crypt crypt) { + super(cmd, RECV_PACKET_SIZE, PARAM_SIZE, AUTH_LEVEL, data, packet, sha1, hmacSha1, crypt); + } + + public short core(byte[] data, short dataOffset, short dataLength) { + byte[] ee_udata = this.m_ee_data.getUdata_ee(); + byte[] ramD_encUdata = this.m_ee_data.getGeneralBuffer_ramD(); + if (ramD_encUdata.length < ee_udata.length) + return AppConfig.A7_FAIL; + + short ramD_encSize = encData(ee_udata, (short) 0, (short) ee_udata.length, ramD_encUdata, (short) 0); + if (ramD_encSize < ee_udata.length) + return AppConfig.A7_FAIL; + + this.m_ramD_outDataInfo[AppConfig.SEND_BUUFER_INFO_OFFSET] = 0; + this.m_ramD_outDataInfo[AppConfig.SEND_BUUFER_INFO_SIZE] = ramD_encSize; + Util.arrayCopyNonAtomic(ramD_encUdata, this.m_ramD_outDataInfo[AppConfig.SEND_BUUFER_INFO_OFFSET], + this.m_ramD_outData, this.m_ramD_outDataInfo[AppConfig.SEND_BUUFER_INFO_OFFSET], + this.m_ramD_outDataInfo[AppConfig.SEND_BUUFER_INFO_SIZE]); + + return AppConfig.A7_SUCCESS; + } +} diff --git a/src/sega/a7/UdataWrite.java b/src/sega/a7/UdataWrite.java new file mode 100644 index 0000000..b315c19 --- /dev/null +++ b/src/sega/a7/UdataWrite.java @@ -0,0 +1,32 @@ +package sega.a7; + +import javacard.security.MessageDigest; + +public class UdataWrite extends AuthCommand { + private static final short RECV_PACKET_SIZE = 62; + private static final byte AUTH_LEVEL = 2; + private static final short PARAM_SIZE = 46; + + public UdataWrite(short cmd, AppData data, MakePacket packet, MessageDigest sha1, HmacSha1 hmacSha1, Crypt crypt) { + super(cmd, RECV_PACKET_SIZE, PARAM_SIZE, AUTH_LEVEL, data, packet, sha1, hmacSha1, crypt); + } + + public short core(byte[] data, short dataOffset, short dataLength) { + if (this.m_ee_data.getSflag_ee()) + return AppConfig.A7_EEPWRITE_DISABLE; + + short ramD_dataSize = AppConfig.UDATA_SIZE; + byte[] ramD_newUdata = this.m_ee_data.getGeneralBuffer_ramD(); + if (ramD_newUdata.length < ramD_dataSize) + return AppConfig.A7_FAIL; + + short ramD_decSize = decData(data, (short) (dataOffset + 6), ramD_dataSize, ramD_newUdata, (short) 0); + + if (ramD_dataSize > ramD_decSize) + return AppConfig.A7_FAIL; + if (!this.m_ee_data.setUdata_ee(ramD_newUdata, (short) 0, ramD_dataSize)) + return AppConfig.A7_EEP_WRITEFAIL; + + return AppConfig.A7_SUCCESS; + } +} diff --git a/src/sega/a7/VerGet.java b/src/sega/a7/VerGet.java new file mode 100644 index 0000000..74c0e0f --- /dev/null +++ b/src/sega/a7/VerGet.java @@ -0,0 +1,24 @@ +package sega.a7; + +import javacard.framework.Util; +import javacard.security.MessageDigest; + +public class VerGet extends Command { + private static final short RECV_PACKET_SIZE = 26; + private static final short PARAM_SIZE = 28; + + public VerGet(short cmd, AppData data, MakePacket packet, MessageDigest sha1) { + super(cmd, RECV_PACKET_SIZE, PARAM_SIZE, data, packet, sha1); + } + + public short core(byte[] data, short dataOffset, short dataLength) { + byte[] ramD_version = this.m_ee_data.getGeneralBuffer_ramD(); + Util.setShort(ramD_version, (short) 0, AppConfig.VERSION); + this.m_ramD_outDataInfo[0] = 0; + this.m_ramD_outDataInfo[1] = 2; + Util.arrayCopyNonAtomic(ramD_version, this.m_ramD_outDataInfo[0], this.m_ramD_outData, + this.m_ramD_outDataInfo[0], this.m_ramD_outDataInfo[1]); + + return AppConfig.A7_SUCCESS; + } +}