AES шифрування і Android клієнт



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

Терміново впроваджуємо новий функціонал. Всі необхідні параметри для побудови бізнес-моделі, в цілях безпеки, будуть передаватися в зашифрованому вигляді AES/CBC/PKCS5Padding з вектором ініціалізації AAACCCDDDYYUURRS і ключем шифрування ZZHHYYTTUUHHGGRR. Приклад зашифрованих даних:

p+oJjsGEULNSptP5Sj1BM5w65hMjkqzahOrd8ybikqyjd0v/608c1tYuKIvDLUIa
 
RQ9jQ6+EwbyMFjlMa6xuEnxOx4sez001hd3NsLO7p00xotqavi9zwubii+
 
nPphP6Zr0P4icvODpmhlmRILgSBsUf1H/3VN1lNXjo4LTa
 
GxLqW3VSg9iV9yFq4VMWqsRF
 

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

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

Трохи теорії про AES шифрування
Advanced Encryption Standard (AES) — симетричний алгоритм блочного шифрування, прийнятий урядом США на основі результатів проведеного конкурсу в якості стандарту шифрування і замінив собою менш надійний алгоритм Data Encryption Standard (DES). Затверджений алгоритм в якості єдиного стандарту шифрування став повсюдно застосовуватися для захисту електронних даних.

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

Криптографічний ключ для алгоритму AES являє собою послідовність з 128, 192 або 256 біт. Інші параметри вхідних та вихідних даних та криптографічного ключа не допускається стандартом AES.

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

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

Приклад розрахунку часу на злом шіфротекстаТаблиця 1: Залежність кількості комбінацій від довжини ключа
Розмір ключа
Можлива кількість комбінацій
1 біт
2
2 біта
4
4 біта
16
8 біт
256
16 біт
65536
32 біта
4.2 * 10^9
56 біт (DES Алгоритм)
7.2 * 10^16
64 біта
1.8 * 10^19
128 біт (AES алогритм)
3.4 * 10^38
192 біта (AES алогритм)
6.2 * 10^57
256 біт (AES алогритм)
1.1 * 10^77
Найшвидший суперкомп'ютер: 10,51 ПетаФлопс = 10,51 х 10^15 Флопс (операцій з плаваючою крапкою в секунду)

Нехай приблизну кількість операцій в секунду, необхідних для перевірки комбінації оптимістично буде: 1000

Кількість перевірок комбінації в секунду = (10,51 х 10^15) / 1000 = 10,51 х 10^12

Кількість секунд, протягом одного року = 365 х 24 х 60 х 60 = 31536000

Кількість років, щоб зламати AES з 128-бітовим ключем = (3,4 х 10^38) / [(10,51 х 1012) х 31536000] = (0,323 х 10^26) / 31536000 = 1,02 х 10^18 = 1 мільярд мільярдів років.

За матеріалами: How is secure AES against brute force attacks?

Докладний опис алгоритму англійською мовою: ADVANCED ENCRYPTION STANDARD
Також можна почитати цю чудову статтю: Як влаштований AES

Вектор ініціалізації
Initialization vector (IV) — вектор ініціалізації, являє собою довільне число, яке може бути використане разом з секретним ключем для шифрування даних.

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

Математична основа
згадування вивчення математичної основи, скористаємося матеріалом з документації до алгоритму ADVANCED ENCRYPTION STANDARD, а також цим хорошим матеріалом російською мовою: Загальний опис криптоалгоритма AES

Відповідно, для опису алгоритму використовується кінцеве поле Галуа GF(2^8), побудоване як розширення поля GF(2) = {0,1} по модулю непривідного многочлена m(x) = x^8 + x^4 + x^3 + x + 1. Елементи поля GF(2^8) є многочлен виду

b_7 · x^7 + b_6 · x^6 + b_5 · x^5 + b_4 · x^4 + b_3 · x^3 + b_2 · x^2 + b_1 · x + b_0

Операції в полі виконуються по модулю m(x). Всього в полі GF(2^8) налічується 2^8 = 256 многочленів.

Основні математичні операції в полі GF(2^8)
  1. Додавання байт можна виконати будь-яким з трьох способів:
    • уявити байти бітовими многочленами та скласти їх за звичайним правилом додавання многочленів з подальшим приведенням коефіцієнтів суми по модулю 2 (операція XOR над коефіцієнтами);
    • підсумовування по модулю 2 відповідні біти в байтах;

    • скласти байти в шістнадцятковій системі числення.
  2. Множення байт виконується за допомогою представлення їх
    многочленами та перемноження за звичайним алгебраїчним правилами.
    Отримане твір необхідно привести по модулю многочлена m(x) = x^8 + x^4 + x^3 + x + 1 (результат приведення дорівнює залишку від ділення добутку на m(x))
  3. Для будь-якого ненульового бітового многочлена b(x) у полі GF(2^8)
    існує многочлен b^-1(x), зворотний до нього за
    множення, тобто b(x) · b^-1(x) = 1 mod m(x)
Многочлен з цілими коефіцієнтами, що належать полем GF(2^8)
Многочлени третього ступеня з коефіцієнтами з кінцевого
поля a_i ∈ GF(2^8) мають вигляд: a(x) = a_3 · x^3 + a_2 · x^2 + a_1 · x + a_0 (1)

Таким чином, в цих многочлени в ролі коефіцієнтів при невідомих задіяні байти замість біт. Далі ці многочлени будемо представляти у формі слова [a_0, a_1, a_2, a_3]. У стандарті AES при множенні многочленів виду (1) використовується приведення по модулю іншого многочлена x^4 + 1.

Для вивчення арифметики розглянутих багаточленів введемо додатково многочлен b(x) = b_3 · x^3 + b_2 · x^2 + b_1 · x + b_0, де b_i ∈ GF(2^8). Тоді
  1. Додавання
    a(x) + b(x) = (a_3 ⊕ b_3) x^3 + (a_2 ⊕ b_2) x^2 + (a_1 ⊕ b_1) x + (a_0 ⊕ b_0)
  2. Множення
    Для представлення результату четырехбайтовым словом, береться результат по модулю многочлена степеня не більше 4. Автори шифру вибрали для цієї мети многочлен x^4+1, для якого справедливо x_i mod(x^4 + 1) ≡ x_i mod 4. Подальше приведення по модулю x^4+1 дозволяє отримати результат у вигляді:

    d(x) = a(x) · b(x) = d_3 · x^3 + d_2 · x^2 + d_1 · x + d_0
Параметри шифрування
Ну що є AES і вектор ініціалізації стало зрозуміло. Тепер спробуємо зрозуміти й інші слова в рядку AES/CBC/PKCS5Padding

Cipher block chaining (CBC) — режим зчеплення блоків шіфротекста — один з режимів шифрування для симетричного блокового шифру з використанням механізму зворотного зв'язку. Кожен блок відкритого тексту (крім першого) побитово складається по модулю 2 з попереднім результатом. Одна помилка в біті блоку шіфротекста впливає на розшифровку всіх наступних блоків. Перебудова порядку блоків зашифрованого тексту викликає пошкодження результату дешифрування.


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

Для працездатності всіх параметрів шифрування AES, кожна реалізація платформи Java повинна підтримувати такі стандартні алгоритми шифрування з ключовими розмірами (в дужках):

Standard Cipher transformations
  • AES/CBC/NoPadding (128)
  • AES/CBC/PKCS5Padding (128)

  • AES/ECB/NoPadding (128)
  • AES/ECB/PKCS5Padding (128)
  • DES/CBC/NoPadding (56)
  • DES/CBC/PKCS5Padding (56)
  • DES/ECB/NoPadding (56)
  • DES/ECB/PKCS5Padding (56)
  • DESede/CBC/NoPadding (168)
  • DESede/CBC/PKCS5Padding (168)
  • DESede/ECB/NoPadding (168)
  • DESede/ECB/PKCS5Padding (168)
  • RSA/ECB/PKCS1Padding (1024, 2048)
  • RSA/ECB/OAEPWithSHA-1AndMGF1Padding (1024, 2048)
  • RSA/ECB/OAEPWithSHA-256AndMGF1Padding (1024, 2048)


Джерело: Cipher

Скринька просто відкривався

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

На відміну від стандартного набору JDK, для роботи нам знадобиться android.util.Base64 для перетворення рядка:

import android.util.Base64;

import java.security.GeneralSecurityException;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public static String decrypt(String key, String iv, String encrypted)
throws GeneralSecurityException {

//Перетворення вхідних даних у масиви байтів

final byte[] keyBytes = key.getBytes();
final byte[] ivBytes = iv.getBytes();

final byte[] encryptedBytes = Base64.decode(encrypted, Base64.DEFAULT);

//Ініціалізація та завдання параметрів розшифровки

SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(ivBytes));

//Розшифровка

final byte[] resultBytes = cipher.doFinal(encryptedBytes);
return new String(resultBytes);
}


Варто також брати до уваги, що розмір вектора ініціалізації повинен бути 16 байт (128 — біт). Це пов'язано з тим, що стандарт шифрування AES включає в себе три типи блокових шифрів: AES — 128, AES — 192 і AES — 256. Кожен з цих шифрів має 128 — бітний розмір блоку, з розмірами ключа 128, 192 і 256 біт відповідно і беручи до уваги те, що для всіх типів блокового шифру, вектор ініціалізації такого ж розміру, як і розмір блоку шифру ми отримуємо, що вектор ініціалізації завжди має 128 — бітний розмір.

В іншому випадку, навіть якщо ми спробуємо використати вектор іншого розміру, то шифротекст не буде розшифрований і ми отримаємо наступне виняток:

java.security.InvalidAlgorithmParameterException: Wrong IV length: must be 16 bytes long


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

Для найдопитливіших — під спойлером те, що зашифровано у повідомленні:

відповідь до задачці
{
"items": [
{
"name": "star",
"color": "green",
"id": 21
},
{
"name": "dog",
"color": "brown",
"id": 43
}
],
"lucky_item_id": 43
}



Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.