Здравствуйте, всем и вся.
SIM-карта является неотьемлемой частью телефона. Раз так... и про программирование SIM-карт тоже можно написать, что касаемо локации).
О SIM-карте
SIM-карта - это более частный случай смарт карты. По своему строению это миниатюрный и защищенный от несанкционированного вмешательства микрокомпьютер со своими системами хранения памяти: ROM, EEPROM, RAM, NVRAM.
А также со своими генераторами случайных чисел и аппаратной реализацией алгоритмов шифрования.
Одними из основных функции SIM-карт в телефоне:
Изначально разработка приложений для SMART-карт всегда было непростым делом. Разные карты разных производителей имели разную внутреннюю структуру, хотя карты все похожие). Каждый производитель карт предоставляет свои средства и студии для разработки программных продуктов. И как правило разработка и сам язык написания специфичен. Сторонние фирмы проективарония ПО практически лишены возможности создавать самостоятельно собственные продукты и продавать их потребителям. Отсюда также "вытекает" следующие трудности и проблемы:
Язык java в данной технологии по своей урезанности находится в цепочке (в сторону уменьшения функциональности): Java->JavaMe->Java Card.
То есть язык очень сильно ограничен по своим функциям. Из типов данных есть однобайтовый boolean и byte, двухбайтовый short.
Int не встречался, но если надо реализовать вам, к примеру для хранения больших сумм валюты в приложении, то рекомендуется просто использовать массив из 4-х byte.
Помимо первостепенных ограничений, которые накладывает технология Java Card, есть рекомендации и правила по созданию программ вплоть до того, как выделять память для временных объектов и прочее.
Основные и важные позиции в этих правилах:
В сети internet информации о разработке для Java Card не так уж сильно много, но все-таки что-то есть.
Но как правило это обзорные статьи как создавать аплет для работы с внешним миром через APDU команды.
В IDE NetBeans поддержка Java Card происходит просто - установки дополнительного модуля.
Даже есть маленькая инструция для данной студии.
Для создания аплета без интерфейса этого предостаточно. APDU консольный симулятор имееется.
В IDE Eclipse начать программировать для Java Card так же достаточно просто.
Пересказывать не буду, просто укажу ссылку на инструкцию. APDU консольный симулятор имееется.
То есть для создания простого Java Card аплета предостаточно только поставить набор инструментов для java card и всё (Development Kit for the Java Card). Не забываем проверить версию Java Card на самой смарт-карте.
На момент написания статьи актуальная версия была 2.2.1, была конечно уже и 3 версия, но её продвижение было какое-то неактивное.
Для написания SIM Toolkit приложений (это различные менюшки, диалоги, обработки звонков и прочее)
надо бы прочесть стандарты 3GPP TS 43.019
и 3GPP TS 11.14.
Первая спецификация объясняет саму архитектуру GSM Java Card, SIM Toolkit Framework, какие команды и события есть в данной среде.
Вторая - непосредственно "рассказывает" все события и методы с их детальным описанием и назначением. При разработке аплета мы будем часто к последней спецификации обращаться.
Далее в проект под SIM Toolkit скачиваем архив бибилиотеки. Подключаем имеющиеся файлы к проекту.
Подключение всегда своеборазно для каждой студии разработки. Затрагивать в рамках данной статьи я не буду.
Тут надо заметить, что тестирование SIM Toolkit аплетов затруднительно в рамках вышеперечисленных студиях NetBeans и Eclipse, так как у них нет полноценных GSM, 3G симуляторов.
Конечно можно всё это симулировать через APDU симулятор ибо SIM Toolkit Framework это надстройка над Java Card просто APDU тут завуалировано красивыми функциями и интерфесами.
Но этот способ для конкретных парней-фанатов).
Как мне известно полноценные симуляторы, которые позволяют проверить sim аплет, не отходя от компьюетра, имеются у фирм разработчиков тесно связанных со смарт - картами.
К примеру это: Gemalto, Sagem Orga.
Хватит болтать! пора бы показать всё)
Далее приводится код с учетом того, что вы знаете базовые основы программирования Java Card
Далее приведем несколько способов, которые позволяют получить программе на сим карте параметры сотовой сети, благодаря которым можно однозначно идентифицировать местоположение абонента в сети. Этими параметрами будут:
public static final byte DEV_ID_ME = 0x82; // смотрим файл в пакете sim.toolkit ToolkitConstants.java
public static final byte RES_CMD_PERF = 0x00; // смотрим файл в пакете sim.toolkit ToolkitConstants.java
...
private final static byte lenLocationInfo = 0x07;
private byte resultByte;
private byte[] tempBuffers;
...
private void getCurrentLocation (ProactiveHandler proHdlr, byte[] locationInfo, short offsetBufferLocationInfo) {
try {
//1 - PRO_CMD_PROVIDE_LOCAL_INFORMATION - Тег выполняемой проактивной команды.
//2 - 0x00 - Надстройка команды.
//3GPP TS 11.14 (Раздер 12.6 Command detais). Возможные значения:
//0x00 - получение location information
//0x01 - полчуение IMEI устройства
//0x02 - получение списка каналов BCCH
//0x03 - получение времени, даты, зоны
//0x04 - настройки языка устройства
//0x05- полчуение Timing Advance - в сети/не сети
//0x06-0x0F - резерв
//3 - DEV_ID_ME - идентификатор устройства.
//3GPP TS 11.14 (Раздер 12.7 Device identities). Возможные значения устройтва, кому отправляется команда:
//0x01 - клавиатура
//0x02 - монитор
//0x03 - динамик
//0x81 - сим карта
//0x82 - мобильный терминал (телефон)
//0x83 - сеть
//0x10 - 0x17 - номера кард ридеров от 0 до 7
//0x21 - 0x27 - номера каналов от 1 до 7
//остальные значение - это резевр
proHdlr.init (PRO_CMD_PROVIDE_LOCAL_INFORMATION, (byte)0x00, DEV_ID_ME);
resultByte = proHdlr.send();//выполняем команду
//возможные ответы в таблице - 3GPP TS 11.14 (Раздел 6.11 Proactive commands versus possible Terminal response)
if (resultByte == RES_CMD_PERF) {
//если успешно, читаем ответ...
ProactiveResponseHandler rspHdlr = ProactiveResponseHandler.getTheHandler();
//Ответ команду PRO_CMD_PROVIDE_LOCAL_INFORMATION с идентификатором 0x00 будет Simple-TLV согласно 3GPP TS 11.14 (Раздел 12.19 Location Information)
rspHdlr.findAndCopyValue (TAG_LOCATION_INFORMATION, locationInfo, offsetBufferLocationInfo);
//Итого боевая часть ответа всего 7 байт
//locationInfo[offsetBufferLocationInfo]...locationInfo[offsetBufferLocationInfo + 1] = MCC
//locationInfo[offsetBufferLocationInfo + 2] = MNC
//locationInfo[offsetBufferLocationInfo + 3]...locationInfo[offsetBufferLocationInfo + 4] = LAC
//locationInfo[offsetBufferLocationInfo + 5]...locationInfo[offsetBufferLocationInfo + 6] = CID
} else {
//Обнуляем массив с ожидаемого смещения и определенной длины
Util.arrayFillNonAtomic (locationInfo, offsetBufferLocationInfo, lenLocationInfo, (byte)0x00);
}
} catch (ToolkitException tkException) {
//Обнуляем массив с ожидаемого смещения и определенной длины
Util.arrayFillNonAtomic (locationInfo, offsetBufferLocationInfo, lenLocationInfo, (byte)0x00);
}
}
....
//вызов метода getCurrentLocation в проекте
//не забываем проинициализировать буфер tempBuffers в методе install аплета
//к примеру: tempBuffers = JCSystem.makeTransientByteArray ((short)0x32, JCSystem.CLEAR_ON_DESELECT);
....
getCurrentLocation (ProactiveHandler.getTheHandler(), tempBuffers, (short)0x00);
....
...
private ToolkitRegistry reg;
private byte resultShort;
private byte[] tempBuffers;
...
public static final byte EVENT_CALL_CONTROL_BY_SIM = 0x09; // смотрим файл в пакете sim.toolkit ToolkitConstants.java
//в конструкторе класса, который наледован от javacard.framework.Applet, прописываем:
reg = ToolkitRegistry.getEntry();
reg.setEvent(EVENT_CALL_CONTROL_BY_SIM);
tempBuffers = JCSystem.makeTransientByteArray ((short)0x32, JCSystem.CLEAR_ON_DESELECT);
...
/**
* Method called by the SIM Toolkit Framework
* @param event the byte representation of the event triggered
*/
public void processToolkit (byte event) {
...
if (event == EVENT_CALL_CONTROL_BY_SIM) {
EnvelopeHandler envHdlr = EnvelopeHandler.getTheHandler();
//Согласно 3GPP TS 11.14 (Раздел 9.1.6) мы можем извлечь из события перехваченного звонка: номер, субномер(опционально), информацию о параметрах сети.
resultShort = envHdlr.getValueLength();
envHdlr.findAndCopyValue (TAG_ADDRESS, tempBuffers, (short) 0);//номер телефона в формате ADN
envHdlr.findAndCopyValue (TAG_LOCATION_INFORMATION, tempBuffers, resultShort);//наши любимые 7 байт информации о локации
//по итогу получаем:
//tempBuffers[0]...tempBuffers[resultShort] - номер телефона в формате ADN
//tempBuffers[resultShort]...tempBuffers[resultShort + 1] = MCC
//tempBuffers[resultShort + 2] = MNC
//tempBuffers[resultShort + 3]...tempBuffers[resultShort + 4] = LAC
//tempBuffers[resultShort + 5]...tempBuffers[resultShort + 6] = CID
}
...
}
...
public static final short FID_MF = 0x3F00; // смотрим файл в пакете sim.access SIMView.java
public static final short FID_DF_GSM = 0x7F20; // смотрим файл в пакете sim.access SIMView.java
public static final short FID_EF_LOCI = 0x6F7E; // смотрим файл в пакете sim.access SIMView.java
...
private final static byte lenLocationInfo = 0x05;
private SIMView gsmFile;
private byte resultShort;
private byte[] tempBuffers;
...
//в конструкторе класса, который наледован от javacard.framework.Applet, прописываем:
gsmFile = SIMSystem.getTheSIMView();
tempBuffers = JCSystem.makeTransientByteArray ((short)0x32, JCSystem.CLEAR_ON_DESELECT);
...
private void getCurrentLocation(byte [] locationInfo, short offsetSourceLocationInfo) {
try {
//последовательно выбираем файл EF LOCI, начиная от корневого главного мастер файла.
gsmFile.select((short)SIMView.FID_MF);
gsmFile.select((short)SIMView.FID_DF_GSM);
gsmFile.select((short)SIMView.FID_EF_LOCI);
//читаем содержимое файла. Читаем методом readBinary т.к. EF LOCI имеет тип обычного прозрачного файла (Transparent EF).
gsmFile.readBinary((short)0x04, locationInfo, offsetSourceLocationInfo, lenLocationInfo);//прочитали буффер размером 5 байт и со смещения равным 4 т.к. TMSI нам не нужно.
} catch (SIMViewException a) {
//Обнуляем массив с ожидаемого смещения и определенной длины
Util.arrayFillNonAtomic (locationInfo, offsetSourceLocationInfo, lenLocationInfo, (byte)0x00);
} catch (ToolkitException a) {
//Обнуляем массив с ожидаемого смещения и определенной длины
Util.arrayFillNonAtomic (locationInfo, offsetSourceLocationInfo, lenLocationInfo, (byte)0x00);
}
}
...
}
Послесловие
Вот и подошло к концу наше повествование. Мы рассмотрели с вами всё, что хотели. Конечно тут всё сжато и некоторые данные (особенно в коде) появляются откуда не возьмись. Мы готовы ответить на все ваши дополнительные вопросы по почте.
Хотелось бы вас посвятить в планы по статьям, которые у нас намечаются (по крайней мере я так думаю и предполагаю).
Есть желание: подробнее написать про APDU команды и про файловую систему сим карты, плотно используя в качестве теоретического материала GSM TS 11.11.
Всем пока и до скорых встреч.