Шифрування даних в мобільних додатках

Перед початком роботи


Про цей посібник


Турбота про безпеку існує завжди, тому в програмному забезпеченні потрібно враховувати необхідність захисту конфіденційних даних. Мобільні програми не є невразливими. Фактично, мобільні пристрою та їх програмне забезпечення мають особливість, яка полягає в тому, що більшість людей носить свої пристрої з собою постійно.


У цьому посібнику подано огляд шифрування даних в Java 2 Micro Edition J2ME-додатку (Java 2 Micro Edition) (MIDlet). Керівництво починається з короткого вступу до шифрування даних. Шифрування – Це тема не для слабких духом; даний розділ досить стислий і присвячений, в основному, API шифрування з відкритим вихідним кодом, написаним Legion of Bouncy Castle. Тема завершується розробкою мідлета (MIDlet), що демонструє шифрування і дешифрування текстових рядків.


Однією проблемою, характерної для більшості мобільних пристроїв, є обмежений обсяг пам'яті. Хоча Bouncy Castle і інші бібліотеки шифрування пропонують багату функціональність, існує також її ціна. Як і в більшості використовуваних вами бібліотеках, тільки невеликі фрагменти коду зазвичай потрібні вашому додатку. Одним з традиційних способів видалення невикористаного коду, одночасно роблячи додаток більш важким для зворотного аналізу, є використання Java-обфуськатор (obfuscator – компонент, що виконує процедуру засекречування class-файлів Java). Я познайомлю вас з обфуськатор з відкритим вихідним кодом – ProGuard. Ми розглянемо всі, починаючи з завантаження та встановлення і закінчуючи конфігуруванням J2ME Wireless Toolkit для використання ProGuard. У завершальному розділі цього посібника порівнюються розміри JAR-файлу засекреченого (obfuscating) мідлета зі звичайним мідлетом.


Попередні вимоги


Для запуску прикладів цього керівництва вам необхідно наступне програмне забезпечення:



Необхідну програмне забезпечення


Установка програмного забезпечення


Під час роботи з даним керівництвом ви будете використовувати чотири програмних кошти. Почнемо з завантаження кожного з необхідних компонентів.




Установка JDK і Wireless Toolkit


Java Development Kit (JDK)


Для установки JDK використовуйте документацію по JDK. Ви можете вибрати або каталог за замовчуванням, або вказати інший каталог. Якщо ви вибрали інший каталог, запам'ятайте його. Під час встановлення Wireless Toolkit програма спробує виявити Java Virtual Machine (JVM); якщо вона не зможе знайти JVM, з'явиться запит на введення шляху установки JDK.


The Wireless Toolkit (WTK)
Даний посібник грунтується на більш ранній статті developerWorks "Розробка мідлетів за допомогою Wireless Toolkit" (див. розділ "Ресурси"), в якій пояснюються основи створення мідлетів. Це керівництво є чудовою відправною точкою, якщо ви є новачком у Wireless Toolkit.


Wireless Toolkit міститься в одному виконуваному файлі. Запустіть цей файл для початку процесу установки. Рекомендується використовувати каталог за замовчуванням. Однак якщо ви використовуєте інший каталог, обраний вами шлях не повинен містити пробіли.


В кінці кожної теми я розгляну, як налаштувати Wireless toolkit для Bouncy Castle і ProGuard.


Шифрування


Огляд


Після виходу MIDP 2.0 підтримка HTTPS тепер потрібно у всіх реалізації MIDP. Однак, навіть з виходом нової специфікації, пройде якийсь час, поки пристрої, що підтримують MIDP 2.0, стануть повсюдні. Крім того, якщо шифрування даних необхідно вам у самому мобільному пристрої (а не як частина мережевої взаємодії між пристроєм і віддаленої системою), підтримки HTTPS недостатньо.


У даному розділі розглянуті деякі основи того, чому шифрування важливо для мобільних додатків, і наведено короткий вступ до Bouncy Castle, API для шифрування і дешифрування даних з відкритим вихідним кодом. Я завершу цей розділ описом кроків по установці Bouncy Castle, що підготує нас до наступного розділу, в якому ми напишемо мідлет, здатний шифрувати і дешифрувати прості текстові рядки.



Чому важливо шифрування


Разом з розповсюдженням і портативністю мобільних пристроїв виник унікальний набір питань з безпеки. Багато людей носять мобільні телефони. У міру того, як пристрої стають все більш умілими, пропонуючи доступ до корпоративної електронної пошти, баз даних та іншої корпоративної інформації, питання, як захистити цю інформацію, стає пріоритетним.


Якщо пристрій буде викрадено або загублено, з'явиться ризик компрометації конфіденційних даних. Це відноситься не тільки до даних, які знаходяться на пристрої, але й до додатків, які надають доступ до даних на віддаленому сервері.


Крім того, взаємодія по бездротовій мережі з використанням мобільного пристрою формує свій власний набір властивих йому ризиків. Володіючи знаннями та обладнанням, можна перехопити дані майже всюди між вашим пристроєм і оконечной точкою вашого взаємодії.


Хоча предметом розгляду в цьому посібнику є, головним чином, шифрування даних на мобільних пристроях, важливо розуміти, що це тільки один крок в забезпеченні конфіденційності.



Ключі


Так само як звичайний ключ дозволяє вам закривати і відкривати двері вашого будинку, термін ключ (key) при обговоренні шифрування має таку ж аналогію – закриття, або шифрування, даних для обмеження доступу, і відкриття, або дешифрування, даних для дозволу доступу.


У світі шифрування ключ – це ніщо інше, як набір символів або цифр, що використовуються під час процесів шифрування і дешифрування. Ви дізнаєтеся про ключі докладніше при обговоренні шифрів.



Шифри


Шифр – це спосіб перетворення конфіденційної інформації в зашифрований формат. Для даного обговорення уявляйте шифр ні чим іншим, як алгоритмом. Так само як існує велика кількість алгоритмів сортування даних у комп'ютері (бульбашкова сортування, швидке сортування і т.д.), існує багато алгоритмів для шифрування і дешифрування даних.


Типи шифрів


Шифри можуть бути симетричними чи асиметричними. Симетричні шифри використовують один і той же ключ для шифрування і дешифрування даних, і часто називаються системами з секретним ключем. Тобто, значення ключа зберігається в секреті двома учасниками – тим, хто шифрує дані, і тим, хто дешифрує їх.


В асиметричних шифри використовуються два різних ключа: один для шифрування і один для дешифрування. Такі системи називаються системами з відкритим ключем, що означає загальнодоступність ключа для шифрування даних. Інакше кажучи, кожен має доступ до ключа для шифрування інформації, але тільки що має закритий ключ може дешифрувати дані.



Алгоритми


Існує велика плутанина, пов'язана з шифруванням. Це стосується і вибору алгоритму, який часто називають механізмом (engine). Існує безліч доступних алгоритмів, ось лише кілька з них:



Жоден алгоритм не є найкращим. Деякі зламані, тоді як інші були замінені більш ефективними алгоритмами. Рішення про те, який алгоритм використовувати – це не точна наука. Я б рекомендував попрацювати з даними керівництвом, для того щоб дізнатися, як використовувати шифрування у мідлет із застосуванням Bouncy Castle. Після освоєння основ процесу ви можете досліджувати різні алгоритми і вирішити, якою є найкращим для вимог вашої програми.



Огляд Bouncy Castle


Bouncy Castle – це Java API для шифрування і дешифрування даних з відкритим вихідним кодом. Bouncy Castle є провайдером Java Cryptography Extension (JCE). JCE – це необов'язковий пакет, що забезпечує підтримку шифрів, ключів і аутентифікацію повідомлень в Java 2 Platform, Standard Edition (J2SE). По суті, провайдер пропонує один або кілька алгоритмів для шифрування і дешифрування даних.


На сьогоднішній день Bouncy Castle підтримує більше 20 механізмів. Це звучить добре, оскільки забезпечується більша гнучкість у способі шифрування даних. З іншого боку, доводиться платити об'ємом коду: Bouncy Castle займає понад 900 KB. На щастя, тільки частину API використовується в один і той же момент часу. І, як ви побачите далі в цьому керівництві, я видалю всі класи, методи і поля, які не потрібні для використання шифратора.



Установка Bouncy Castle


Для додавання підтримки Bouncy Castle під всі програми, які розробляються в WTK, розархівуйте файл midp_classes.zip в каталозі C: WTK21appslib. Якщо ви хочете обмежити використання бібліотеки Bouncy Castle і додати її підтримку тільки для конкретного проекту, розархівуйте ZIP-файл у каталог lib вашого проекту. Наприклад, якщо б ви створили проект EncryptTest, то повинні були б розархівувати файл midp_classes.zip в каталог C: WTK21appsEncryptTestlib.


Після приміщення Bouncy ZIP-файлу в потрібне місце, ви можете додати необхідні вираження import для будь-яких класів, обраних для використання у вашому мідлет. WTK знайде class-файли та включить їх у ваш пакетований мідлет.



Резюме по розділу


У даному розділі було розглянуто шифрування і причини, чому воно є важливим при розробці мобільних додатків. Були розглянуті також деякі ключові концепції шифрування, такі як шифри і ключі, і перераховано кілька добре відомих алгоритмів шифрування. Я завершив розділ оглядом Bouncy Castle API з відкритим вихідним кодом з подальшим коротким описом процесу його встановлення.


Тепер ви дізнаєтеся про те, як використовувати Bouncy Castle API у мідлет.


Мідлет EncryptText


Основні етапи шифрування


Існує багато алгоритмів, стандартів і процесів для захисту даних. Моя мета полягає не в детальному обговоренні шифрування, а в демонстрації декількох простих кроків для забезпечення елементарного шифрування у мідлет. Ви повинні розуміти, що для гарного захисту ваших додатків вам знадобиться набагато більш трудомістка і добре спланована робота. Даний огляд наведено просто для того, щоб ви почали роботу, і демонструє стандартний спосіб шифрування інформації.


Для шифрування текстової рядки я буду виконувати наступні дії:



  1. Вибрати механізм шифрування і розмістити примірник цього механізму.
  2. Записати шіфруемий текст у байтовий масив.
  3. Ініціалізувати шифр ключем.
  4. Викликати механізм шифрування для шифрування даних.

Як ви можете здогадатися, дешифрування даних – це аналогічний процес:



  1. Зберегти дешіфруемий текст у байтовий масив.
  2. Ініціалізувати шифр ключем.
  3. Викликати механізм для дешифрування даних.

Представляючи в пам'яті цю загальну картину, я напишу мідлет, щоб продемонструвати використання Bouncy Castle API.



Огляд мідлета: запит тексту


Кращим способом дізнатися, як шифрувати дані за допомогою Bouncy Castle, є створення мідлета для демонстрації основ. Цей приклад буде відображати TextBox для введення користувачем рядка для шифрування. Тут буде три варіанти меню: Encrypt, Decrypt і Exit. Далі наведено кілька ілюстрацій, які показують, як виглядає мідлет у емуляторі WTK. На малюнку 1 показаний мідлет і TextBox, який буде містити текст для шифрування / дешифрування.


Малюнок 1. Запит тексту



Огляд мідлета: шифрування тексту


Після введення тексту виберіть в меню варіант Encrypt. Текст буде пропущений через шифрувальний механізм Bouncy Castle, а потім TextBox буде оновлено зашифрованим текстом. На малюнку 2 показані ці два кроки.


Малюнок 2. Шифрування тексту



Огляд мідлета: дешифровка тексту


Останнім кроком є дешифрування вмісту TextBox назад в оригінальну рядок. На малюнку 3 показаний вибір Decrypt з меню разом з отриманим текстом, вміщеним тому в TextBox.


Малюнок 3. Дешифрування тексту



Створення мідлета


Нижче перераховані кроки, яким я наслідував при створенні мідлета в WTK:



  1. Створити проект.
  2. Написати вихідний код.
  3. Відкомпілювати і попередньо перевірити код.
  4. Запустити мідлет.

У наступному розділі показано, як почати створення нового проекту.



Створення проекту



  1. Виберіть New Project.
  2. Введіть назву проекту і назва класу мідлета, як показано на малюнку 4.
  3. Виберіть Create Project.

Малюнок 4. Створення проекту EncryptText




Написання Java-коду


Для даного мідлета є один файл з Java-кодом: EncryptText.java.


Скопіюйте наступний код EncryptText.java в текстовий редактор:






  /*————————————————–
* EncryptText.java
*
* Мідлет, що демонструє простої шифрування / дешифрування
* Даних програми.
*————————————————-*/
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.engines.IDEAEngine;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.util.encoders.Hex;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class EncryptText extends MIDlet implements CommandListener
{
private Display display; / / Посилання на об'єкт Display
private TextBox tbTest; // Main textbox
private Command cmExit; / / Command для виходу
private Command cmEncrypt; / / Command для шифрування тексту
private Command cmDecrypt; / / Command для дешифрування тексту
private PaddedBufferedBlockCipher cipher = null; / / Шифр
private String key = "x-392kla% 3 $ * 1f"; / / Kлюч

/*————————————————–
* Конструктор
*————————————————-*/
public EncryptText()
{
display = Display.getDisplay(this);

/ / Створити кілька Command.
cmExit = new Command(“Exit”, Command.EXIT, 1);
cmEncrypt = new Command(“Encrypt”, Command.SCREEN, 2);
cmDecrypt = new Command(“Decrypt”, Command.SCREEN, 3);

tbTest = new TextBox(“Text to encrypt/decrypt”,
"IBM developerworks", 250, TextField.ANY);
tbTest.addCommand(cmExit);
tbTest.addCommand(cmEncrypt);
tbTest.addCommand(cmDecrypt);
tbTest.setCommandListener(this);

/ / Створити новий шифр (механізм) для шифрування / дешифрування
cipher = new PaddedBufferedBlockCipher (new CBCBlockCipher (new IDEAEngine ()));
}

public void startApp()
{
display.setCurrent(tbTest);
}

public void pauseApp()
{
}

public void destroyApp(boolean unconditional)
{
}

/*————————————————–
* Обробка подій
*————————————————-*/
public void commandAction(Command c, Displayable s)
{
if (c == cmExit)
{
destroyApp(false);
notifyDestroyed();
}
else if (c == cmEncrypt) // Encrypt text
{
encryptData();
}
else if (c == cmDecrypt) // Decrypt text
{
decryptData();
}
}

/*————————————————–
* Зашифрувати дані з текстового поля. Помістити дані
* Назад в текстове поле по завершенні.
*————————————————-*/
private void encryptData()
{
/ / Отримати вміст з текстового поля
byte[] inBytes = tbTest.getString().getBytes();

/ / Ініціалізувати шифр. "True" вказує шифрування
cipher.init(true, new KeyParameter(key.getBytes()));

/ / Визначити мінімальний розмір вихідної буфера
byte [] outBytes = new byte [cipher.getOutputSize (inBytes.length)];

/ / "Len" – це повернута реальна довжина
int len = cipher.processBytes (inBytes, 0, inBytes.length, outBytes, 0);
try
{
/ / Обробити останній блок у буфері, починаючи з позиції "len"
cipher.doFinal(outBytes, len);

/ / Поновити текстове полі нової зашифрованою рядком
tbTest.setString(new String(Hex.encode(outBytes)));

/ / Зневадження
System.out.println ("encrypted:" + new String (Hex.encode (outBytes)));
}
catch(CryptoException e)
{
System.out.println(“Exception: ” + e.toString());
}
}

/*————————————————–
* Дешифрування даних у текстовому полі. Поміщає дані
* Назад в текстове поле по завершенні.
*————————————————-*/
private void decryptData()
{
/ / Отримати текст для дешифрування з текстового поля
byte [] inBytes = Hex.decode (tbTest.getString (). getBytes ());

/ / Ініціалізація шифру. "False" вказує дешифрування
cipher.init(false, new KeyParameter(key.getBytes()));

/ / Визначити мінімальний розмір вихідної буфера
byte [] outBytes = new byte [cipher.getOutputSize (inBytes.length)];

/ / "Len" – це повернута реальна довжина
int len = cipher.processBytes (inBytes, 0, inBytes.length, outBytes, 0);

try
{
/ / Обробити останній блок у буфері, починаючи з позиції "len"
cipher.doFinal(outBytes, len);

/ / Поновити текстове поле дешифрований рядком
tbTest.setString(new String(outBytes).trim());

System.out.println ("decrypted:" + new String (outBytes). Trim ());
}
catch(CryptoException e)
{
System.out.println(“Exception: ” + e.toString());
}
}

}


При створенні нового проекту WTK створює правильну структуру каталогів за вас. У даному прикладі WTK створив каталог C: WTK21appsEncryptText і необхідні підкаталоги. Збережіть ваш Java-файл із вихідним кодом як EncryptText.java в каталог src, як показано на малюнку 5 (зверніть увагу на те, що назви диску та каталогу WTK можуть відрізнятися в залежності від того, куди ви встановили цей пакет інструментальних програм).


Малюнок 5. Збереження коду EncrpytText



Примітка: У наступних розділах Java-код буде показаний детально.



Збереження, компілювання і попередня перевірка


Виберіть Build для компілювання, попередньої перевірки та пакетування мідлета, як показано на малюнку 6.


Малюнок 6. Компонування проекту EncryptText


Виберіть Run для запуску Application Manager.



Запуск мідлета EncryptText


Для запуску мідлета EncryptText виберіть Launch, Як показано на малюнку 7.


Малюнок 7. Запуск мідлета EncryptText


Зображення в лівій частині малюнка 8 показує оригінальний текст, який буде шифруватися, і варіант меню для початку процесу шифрування. Зображення праворуч показує текст у його зашифрованій формі.


Малюнок 8. Шифрування тексту


У лівій частині малюнка 9 знаходиться зашифрований текст і варіант меню для початку процесу дешифрування. Зображення праворуч показує результати після завершення дешифрування.


Малюнок 9. Дешифрування тексту



Огляд коду: конструктор


Я починаю з визначення команд для обробки подій і TextBox для введення тексту користувачем. Останнім кроком є створення екземпляра шифру. Хоча існує багато механізмів шифрування, доступних в Bouncy Castle, для цього мідлета я вибрав механізм IDEA (International Data Encryption Algorithm).






  public EncryptText()
{
display = Display.getDisplay(this);

/ / Створити кілька Command.
cmExit = new Command(“Exit”, Command.EXIT, 1);
cmEncrypt = new Command(“Encrypt”, Command.SCREEN, 2);
cmDecrypt = new Command(“Decrypt”, Command.SCREEN, 3);

tbTest = new TextBox(“Text to encrypt/decrypt”,
"IBM developerworks", 250, TextField.ANY);
tbTest.addCommand(cmExit);
tbTest.addCommand(cmEncrypt);
tbTest.addCommand(cmDecrypt);
tbTest.setCommandListener(this);

/ / Створити новий шифр (механізм) для шифрування / дешифрування
cipher = new PaddedBufferedBlockCipher (new CBCBlockCipher (new IDEAEngine ()));

/ / Створити ключ
key = new String(“x-392kla%3$*1f”);
}


Процес шифрування, який я вибрав, буде обробляти блоки тексту, тобто, послідовність бітів шифрується як один блок, а ключ застосовується до блоку в цілому. CBCBlockCipher() запитує, щоб поточний шіфруемий блок був об'єднаний з попереднім зашифрованим блоком. З таким підходом однакові шаблони в різних повідомленнях будуть зашифровані в різний текст.


PaddedBufferedBlockCipher() – Це клас-конверт, що забезпечує вирівнювання тексту, що необхідно для підгонки ви обрали для шифрування тексту, розмір якого не дорівнює розміру блоку, оброблюваного алгоритмом шифрування. Наприклад, механізм IDEA обробляє 8-байтниє блоки.


Для шифрування і дешифрування тексту буде використовуватися шифр (cipher), що я незабаром продемонструю.


Останній виклик в конструкторі – розподіл пам'яті для ключа. IDEA є симетричним шифром, це означає, що для шифрування і дешифрування даних використовується один і той самий ключ.



Огляд коду: event handling


Для цього мідлета існує невелика обробка подій для управління. Я викликаю відповідний метод на основі обраного користувачем варіанту.






      public void commandAction(Command c, Displayable s)
{
if (c == cmExit)
{
destroyApp(false);
notifyDestroyed();
}
else if (c == cmEncrypt) / / Шифрувати текст
{
encryptData();
}
else if (c == cmDecrypt) / / Дешифрувати текст
{
decryptData();
}
}

Огляд коду: шифрування даних


Я почав процес шифрування із запису введених користувачем символів (у текстовому полі) байт-масив inBytes. Наступним кроком є ініціалізація шифру, який був розподілений раніше. Першим параметром методу cipher.init() є логічне значення, яке вказує, чи виконується шифрування даних. У залежності від значення цього параметра механізм ініціалізується або для шифрування, або для дешифрування даних. Значення true запитує шифрування, а false вказує дешифрування. Другий параметр cipher.init() – Це ключ, вказаний у вигляді байтового масиву.


outBytes – Це масив, який буде містити результати зашифрованого тексту. Я починаю процес шифрування викликом cipher.processBytes(), Передаючи вхідний і вихідний масиви, а також значення індексів для цих масивів, що вказують, звідки починати читання вхідної інформації і куди записувати вихідну інформацію.






    private void encryptData()
{
/ / Отримати вміст з текстового поля
byte[] inBytes = tbTest.getString().getBytes();

/ / Ініціалізувати шифр. Значення "true" вказує шифрування
cipher.init(true, new KeyParameter(key.getBytes()));

/ / Визначити мінімальний розмір вихідної буфера
byte [] outBytes = new byte [cipher.getOutputSize (inBytes.length)];

/ / "Len" – це повернута реальна довжина
int len = cipher.processBytes (inBytes, 0, inBytes.length, outBytes, 0);
try
{
/ / Обробити останній блок у буфері, починаючи з позиції "len"
cipher.doFinal(outBytes, len);

/ / Поновити текстове полі нової зашифрованою рядком
tbTest.setString(new String(Hex.encode(outBytes)));

/ / Зневадження
System.out.println ("encrypted:" + new String (Hex.encode (outBytes)));
}
catch(CryptoException e)
{
System.out.println(“Exception: ” + e.toString());
}
}


Код всередині блоку try-catch обробляє останній блок у вихідному масиві. Потім я поновлюю TextBox зашифрованим текстом.



Огляд коду: decrypt data


Аналогічно шифруванню, при дешифрування я починаю з запису вмісту TextBox в масив. Я ініціалізували шифр, передаючи в цей раз, як перший параметр, значення false. Це вказує на те, що я не шифрую (тобто, не ініціалізували механізм для дешифрування). Розподіляється вихідний масив і викликається cipher.processBytes() для запуску процесу дешифрування.






    private void decryptData()
{
/ / Отримати текст для дешифрування з текстового поля
byte [] inBytes = Hex.decode (tbTest.getString (). getBytes ());

/ / Ініціалізація шифру. "False" вказує дешифрування
cipher.init(false, new KeyParameter(key.getBytes()));

/ / Визначити мінімальний розмір вихідної буфера
byte [] outBytes = new byte [cipher.getOutputSize (inBytes.length)];

/ / "Len" – це повернута реальна довжина
int len = cipher.processBytes (inBytes, 0, inBytes.length, outBytes, 0);

try
{
/ / Обробити останній блок у буфері, починаючи з позиції "len"
cipher.doFinal(outBytes, len);

/ / Поновити текстове поле дешифрований рядком
tbTest.setString(new String(outBytes).trim());

System.out.println ("decrypted:" + new String (outBytes). Trim ());
}
catch(CryptoException e)
{
System.out.println(“Exception: ” + e.toString());
}
}


Я завершую процес дешифрування оновленням TextBox новими дешифрованими даними.



Резюме по розділу


У цьому розділі ми працювали з API шифрування Bouncy Castle. Я почав з простого дизайну мідлета (нічого, крім TextBox): запит рядка для шифрування і три команди управління – для шифрування, для дешифрування і для виходу з мідлета. Після цього я створив новий проект у WTK, написав Java-код, скомпілював його і виконав попередню перевірку мідлета. Останніми діями були детальний огляд вихідного коду, огляд подробиць обробки даних з використанням Bouncy Castle.


Закінчивши мідлет, я переходжу до теми засекречування.


Засекречування


Огляд


При роботі з мобільними пристроями розмір програми надзвичайно важливий. Показавши, як включити Bouncy Castle API в J2ME-додаток, я, в той же час, додав значний обсяг коду. Багато хто з сучасних мобільних пристроїв просто не змогли б завантажити мідлет через обмежену пам'яті. Ось де приходить на допомогу засекречування (obfuscation).


У даному розділі я почну з короткого огляду засекречування: що це таке, як воно допомагає у зменшенні розміру програми і чому воно є важливим. Я також наведу кроки по налаштуванню обфуськатор ProGuard для використання в WTK. Нарешті, я покажу, як активізувати ProGuard і почати процес генерування засекречених class-файлів.



Що таке засекречування


Зворотний аналіз Java-програм не є важким процесом. Власне кажучи, існують безкоштовні декомпілятором, які роблять роботу за вас. Щоб створити трохи більше труднощів для додатків зворотного аналізу, багато Java-програмісти використовують так звані обфуськатор для перейменування класів, методів і полів. Призначення такого процесу перейменування – зробити вихідний код нечитабельним.


Побічним ефектом процесу засекречування є зменшення розміру class-файлів. Це досягається двома кроками. По-перше, може бути зекономлено несподіване кількість байт при заміні імен класів, методів і полів іменами, що складаються з одного або двох символів. Крім того, обфуськатор видаляють невикористовувані класи, методи і поля. Комбінування цих двох кроків може значно зменшити розмір остаточного додатки. У наступному розділі я виконаю порівняння мідлетів з засекречуванням і без нього, щоб дати вам відчути, заради чого я витратив стільки часу на розмови про це.



Установка ProGuard


WTK має вбудовану середовище для підтримки обфуськатор байт-коду. Якщо у вас встановлена версія 2.1, як було підкреслено в розділі "Установка", ви маєте додаткову вигоду, яка полягає в наявності підключається модуля, спроектованого спеціально для ProGuard.


Встановити ProGuard так само просто, як і розархівувати proguard.jar і зберегти файл у каталозі bin WTK. Наприклад, якщо WTK встановлено в C: WTK21, скопіюйте файл proguard.jar в C: WTK21 in. Див. малюнок 10.


Малюнок 10. Установка ProGuard



Виконання ProGuard: Крок 1


Я розгляну дії щодо виконання ProGuard з WTK. Почнемо з запуску WTK і відкриття мідлета EncryptText. Запустіть процес засекречування, вибравши меню Project -> Package -> Create Obfuscated Package. Див. малюнок 11.


Малюнок 11. Запуск ProGuard



Виконання ProGuard: Крок 2


Кроки для пакетування мідлета включають в себе перекомп всіх вихідних Java-файлів, виконання попередньої перевірки class-файлів і, нарешті, засекречування. На малюнку 12 показаний знімок екрану WTK, що відображає виконання процесу засекречування.


Малюнок 12. Засекречування



Виконання ProGuard: Крок 3


Після завершення засекречування ви повинні знайти JAR-файл, що містить засекречені класи. WTK зберігає всі JAR-файли мідлетів в каталозі bin проекту. Наприклад, для створеного мною в попередньому розділі мідлета ви знайдете JAR в каталозі C: WTK21appsEncryptText in. Див. малюнок 13.


Малюнок 13. Результати ProGuard



Результат засекречування


Щоб мати уявлення про те, на що схожі результати роботи обфуськатор, давайте розглянемо один метод у мідлет до і після засекречування. Метод encryptData(), Написаний раніше, показаний нижче:






    private void encryptData()
{
/ / Отримати вміст з текстового поля
byte[] inBytes = tbTest.getString().getBytes();

/ / Ініціалізувати шифр. Значення "true" вказує засекречування
cipher.init(true, new KeyParameter(key.getBytes()));

/ / Визначити мінімальний розмір вихідної буфера
byte [] outBytes = new byte [cipher.getOutputSize (inBytes.length)];

/ / "Len" – це повернута реальна довжина
int len = cipher.processBytes (inBytes, 0, inBytes.length, outBytes, 0);
try
{
/ / Обробити останній блок у буфері, починаючи з позиції "len"
cipher.doFinal(outBytes, len);

/ / Поновити текстове полі нової засекреченої рядком
tbTest.setString(new String(Hex.encode(outBytes)));

/ / Зневадження
System.out.println ("encrypted:" + new String (Hex.encode (outBytes)));
}
catch(CryptoException e)
{
System.out.println(“Exception: ” + e.toString());
}
}


Нижче ви можете побачити, як виглядає засекречений код:






private void a()
{
byte abyte0[] = f.getString().getBytes();
g.a(true, new b(a.getBytes()));
byte abyte1[] = new byte[g.a(abyte0.length)];
int i = g.a(abyte0, 0, abyte0.length, abyte1, 0);
try
{
g.a(abyte1, i);
f.setString (new String (org.bouncycastle.util.encoders.ab (abyte1)));
System.out.println ("encrypted:" + new String (org.bouncycastle.util.encoders.ab (abyte1)));
}
catch(org.bouncycastle.crypto.b b1)
{
System.out.println(“Exception: ” + b1.toString());
}
}

Очевидно, що його набагато важче прочитати. Зверніть увагу на короткі імена змінних і методів. Це один з методів, які використовує обфуськатор для зменшення розміру програми. Як ви пам'ятаєте, обфуськатор також видаляє невживані класи, методи і поля, що зазвичай є найістотнішим методом видалення великої кількості коду з мідлета.



Резюме по розділу


У цьому розділі був представлений огляд засекречування, у тому числі такі теми: чому засекречування важливо, як працює процес, і як встановити і запустити ProGuard з WTK.


Давайте закінчимо порівнянням розміру мідлетів до засекречування і після.


Об'єднуємо всі разом


Огляд


Тепер ви маєте достатньо інформації для шифрування і дешифрування даних в додатках, а також для засекречування мідлетів. У даному розділі я докладно розгляну, що було зроблено для економії байтів в JAR-файлах з засекречуванням і без нього.


Я почну з розгляду мідлета без засекречування.


Пакетування мідлета


Коли б я не вибрав пункт меню Build в WTK, вихідний Java-код компілюється і перевіряється. Однак за замовчуванням WTK НЕ пакетує мідлет в JAR-файл. Для того щоб побачити розмір мідлета, що включає весь доданий код з додаткових бібліотек, я повинен зазначити WTK спакетіровать весь код. З меню Project виберіть Package / Create Package. Див. малюнок 14.


Малюнок 14. Пакетування мідлета



Розмір спакетірованного мідлета


Для пошуку створеного WTK JAR-файлу перейдіть до каталогу bin проекту EncryptText, наприклад, C: WTK21appsEncryptTestlib. На малюнку 15 показаний розмір файлу – 547 KB. Зайве говорити, що один цей факт робить мідлет марним для багатьох мобільних пристроїв.


Малюнок 15. Розмір спакетірованного мідлета



Засекречування мідлета


Тепер я заново створю JAR-файл, на цей раз запитуючи ProGuard засекретити вміст. З меню Project виберіть Package / Create Obfuscated Package. Див. малюнок 16.


Малюнок 16. Засекречування мідлета



Розмір засекреченого мідлета


Знову знайдіть каталог bin для того щоб побачити розмір JAR-файлу. Ви помітите значну різницю після видалення обфуськатор всіх непотрібних класів, методів і полів. На малюнку 17 видно, що було зекономлено більше 500 KB!


Малюнок 17. Розмір засекреченого мідлета



Стиснення ще на кілька байт


Раніше говорилося, що WTK 2.x попередньо налаштований на роботу з ProGuard. Як ви бачили в цьому посібнику, процес установки мінімальний. Однак, виконавши кілька додаткових дій, ви можете заощадити ще більше байт. Це можна зробити шляхом навіть незначної зміни конфігурації, запитуючи, щоб WTK викликав ProGuard безпосередньо під час процесу пакетування. Відмінність в тому, як викликається ProGuard. При існуючій конфігурації WTK, коли ви запитуєте пакетування / засекречування з ProGuard, конфігураційний файл записується на диск, в той час як окрема віртуальна машина читає файл і виконує ProGuard на основі вмісту файлу. При підході, який ви тут побачите, WTK буде викликати ProGuard безпосередньо, пропускаючи необхідність читання та опрацювання конфігураційного файлу.



Стиснення ще на кілька байт, крок 1


По-перше, ви повинні знайти конфігураційний файл ktools.properties. У Windows він знаходиться в каталозі C: WTK21wtklibWindows. На малюнку 18 показано його місце розташування.


Малюнок 18. Конфігураційний файл



Стиснення ще на кілька байт, крок 2


Для запиту прямого виклику ProGuard в WTK ви повинні змінити в конфігураційному файлі рядки, повідомляють WTK кращий клас і classpath для ProGuard. Виконайте зміни в конфігураційному файлі, показані нижче:


Конфігурація за замовчуванням




 obfuscator.runner.class.name: com.sun.kvem.ktools.RunPro
obfuscator.runner.classpath: wtklibktools.zip
obfuscate.script.name:


Оновлена конфігурація




 # Obfuscator.runner.class.name: com.sun.kvem.ktools.RunPro
#obfuscator.runner.classpath: wtklibktools.zip
#obfuscate.script.name:

obfuscator.runner.class.name: proguard.wtk.ProGuardObfuscator
obfuscator.runner.classpath: binproguard.jar


Тут я закоментувавши оригінальну конфігурацію і вказав клас і classpath розташування JAR-файлу ProGuard. Це проста зміна призводить до більш ефективного засекречування.


Важливе зауваження: Для того щоб ці зміни вступили в силу, ви повинні перезапустити WTK.



Стиснення ще на кілька байт, крок 3


Після перезапуску WTK створіть засекречений пакет так, як я робив раніше. Тепер знайдіть каталог bin, куди WTK записує засекречений JAR-файл. Якщо ви порівняєте розмір нового JAR-файлу з JAR-файлом з попереднього розділу, то побачите різницю приблизно в 3 K. На малюнках 19 і 20 показані JAR-файли для оригінального мідлета і для нової конфігурації відповідно.


Малюнок 19. Оригінальний засекречений JAR-файл


Використовуючи WTK, викликає ProGuard безпосередньо, ви можете заощадити ще кілька байт.


Малюнок 20. Новий засекречений JAR-файл


Хоча 3 K можуть здатися не дуже значним досягненням, у світі мобільних додатків ця різниця може вплинути на те, завантажиться ваш мідлет у пристрій чи ні.



Резюме по розділу


Крім того, що мидлети стають більш важкими для зворотного аналізу, засекречування може мати значний вплив на розмір вашої програми. У даному розділі ви побачили, скільки зберігається простору після видалення невживаних класів, методів і полів. Для короткого мідлета ця економія склала більше 500 K.


Резюме


У цьому посібнику був представлений огляд захисту мобільних додатків. Воно почалося з короткого обговорення шифрування, включаючи шифри, ключі та алгоритми. Також було розглянуто процес установки API шифрування Bouncy Castle.


Предметом розгляду наступного розділу була розробка мідлета для демонстрації їх використання Bouncy Castle API для шифрування і дешифрування простих текстових рядків. Після цього ви дізналися про засекречування class-файлів. Спеціальна увага була приділена ProGuard, в тому числі, інтеграції цього інструментального засобу з відкритим вихідним кодом у WTK. В останньому розділі посібника було проведено порівняння розмірів JAR-файлів до засекречування class-файлів і після.


Хоча ви тільки поверхнево познайомилися зі створенням захищених мобільних додатків, це керівництво послужить відправною точкою в темі шифрування даних. У вашому розпорядженні також є новий інструмент (Обфуськатор class-файлів) призначений для того, щоб зробити зворотний аналіз вашого застосування більш важким. Не забудьте про здатність обфуськатор видаляти невикористовувані класи, методи і поля, що може призвести до створення значно менших JAR-файлів.

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*