Криптиране на данни на Android, AES-GCM или обикновен AES?

Моят екип трябва да разработи решение за криптиране на двоични данни (съхранени като byte[]) в контекста на приложение за Android, написано на Java. Криптираните данни ще бъдат предавани и съхранявани по различни начини, по време на които не може да се изключи повреда на данните. В крайна сметка друго приложение за Android (отново написано на Java) ще трябва да дешифрира данните.

Вече е решено, че алгоритъмът за криптиране трябва да бъде AES, с ключ от 256 бита. Въпреки това бих искал да взема информирано решение за това коя AES реализация и/или „режим“ трябва да използваме. Четох за нещо, наречено GCM режим, и направихме някои тестове с него (използвайки BouncyCastle/SpongyCastle), но не ми е съвсем ясно за какво точно служи AES-GCM и какво ни „купува“ в сравнение с обикновения AES - и дали има някакви компромиси, които трябва да се вземат предвид.

Ето списък с притеснения/изисквания/въпроси, които имаме:

  • Попълване: данните, които трябва да шифроваме, не винаги ще бъдат кратни на 128-те бита, така че внедряването/режимът на AES трябва да добавя запълване, но само когато е необходимо. Останах с впечатлението, че обикновена реализация на AES, като предоставената от javax.crypto.Cipher, няма да направи това, но първоначалните тестове показаха, че го прави. Така че предполагам, че изискването за подпълване само по себе си не е причина да се прибягва до нещо като GCM вместо "обикновен" AES. Вярно ли е?

  • Удостоверяване: Нуждаем се от надежден начин за откриване на повреда на данните. В идеалния случай обаче искаме да открием и кога е направен опит за декриптиране с неправилен ключ. Следователно искаме да можем да правим разлика между двата случая. Причината, поради която в крайна сметка обмислих GCM на първо място, се дължи на този въпрос за Stackoverflow, където един от отговорилите изглежда предполага че правенето на това разграничение е възможно с помощта на AES-GCM, въпреки че той не предоставя подробно обяснение (да не говорим за код).

  • Минимизиране на разходите: Трябва да ограничим разходите за съхранение и предаване на шифрованите данни. Затова искаме да знаем дали и до каква степен изборът за конкретна реализация/режим на AES влияе върху размера на режийните разходи.

  • Ефективност на криптиране/декриптиране: Въпреки че не е основна грижа, ние се чудим до каква степен изборът на конкретна реализация/режим на AES влияе върху производителността на криптиране и декриптиране, както по отношение на времето на процесора, така и на паметта.

Благодаря предварително за всякакви съвети, разяснения и/или примери за кодове.

РЕДАКТИРАНЕ: delnan услужливо посочи, че няма такова нещо като „обикновен AES“. За да изясня, това, което имах предвид с това, е използването на вградената AES поддръжка на Java.
Така: Cipher localCipher = Cipher.getInstance("AES");


person Matthias    schedule 16.11.2012    source източник
comment
Какво е обикновен AES? Освен ако не работите само с 256 бита данни. Ако имате повече данни от това, вие непременно използвате някакъв режим. Може би вашата библиотека избира един режим по подразбиране (от това, което съм чувал, много библиотеки правят доста несигурен избор тук). Така че трябва да проверите кой режим всъщност се използва, когато използвате обикновен AES.   -  person    schedule 16.11.2012
comment
Благодаря за коментара @delnan, направих редакция, за да изясня какво имах предвид.   -  person Matthias    schedule 23.11.2012


Отговори (1)


През 2012 отговорът е да изберете GCM, освен ако нямате сериозни проблеми със съвместимостта.

GCM е режим на удостоверено шифроване. Той ви осигурява поверителност (криптиране), цялост и удостоверяване (MAC) наведнъж.

Досега нормалните режими на работа бяха ECB (което е по подразбиране за Java ), CBC, CTR, OFB и няколко други. Всички те предоставят само криптиране. Поверителността сама по себе си обаче рядко е полезна без почтеност; човек трябваше да комбинира такива класически режими с проверки на целостта по ad-hoc начин. Тъй като криптографията е трудна за правилна, често такива комбинации са несигурни, по-бавни от необходимото или дори и двете.

Режимите на Удостоверено криптиране са (сравнително наскоро) създадени от криптографи за решаване на този проблем. GCM е един от най-успешните: избран е от NIST, той е ефективен, не е патентован и може да носи Допълнителни удостоверени данни (т.е. данни, които остават ясни, но за които можете да проверите автентичността). За описание на други режими вижте тази отлична статия на Матю зелено.

Стигаме до вашите притеснения:

  • Подложка: по подразбиране Java използва подложка PKCS#7. Това работи, но често е уязвим за атаки на оракули за подпълване, които са най-добре се отстранява с MAC. GCM вече вгражда MAC (наречен GMAC).

  • Удостоверяване: AES-GCM приема само един AES ключ като вход, а не пароли. Той ще ви каже дали AES ключът е грешен или полезният товар е бил манипулиран, но такива условия се третират като едно. Вместо това трябва да обмислите използването на подходящ алгоритъм за извличане на ключ като PBKDF2 или bcrypt, за да извлечете AES ключа от паролата. Не мисля, че винаги е възможно да се каже дали паролата е неправилна или полезният товар е бил променен, тъй като данните, необходими за проверка на първото, винаги могат да бъдат повредени. Можете да шифровате малък известен низ (с ECB AES), да го изпратите заедно и да го използвате, за да проверите дали паролата е правилна.

  • Минимизиране на служебните разходи: В края на деня всички режими водят до еднакви служебни разходи (около 10-20 байта), ако искате удостоверяване. Освен ако не работите с много малки полезни натоварвания, тази точка може да бъде игнорирана.

  • Ефективност: GCM е доста добър, тъй като е онлайн режим (няма нужда да буферирате целия полезен товар, така че по-малко памет), той може да се паралелизира и изисква един AES операция и едно умножение на Галоа на блок с обикновен текст. Класическите режими като ECB са по-бързи (само една AES операция на блок), но - отново - трябва да вземете предвид и логиката на целостта, която в крайна сметка може да се окаже по-бавна от GMAC.

Като каза това, човек трябва да е наясно, че сигурността на GCM разчита на добро генериране на произволни числа за създаване на IV.

person SquareRootOfTwentyThree    schedule 16.11.2012
comment
Току-що тествах някакъв Android код с помощта на AES/EAX на Jelly Bean 4.2. Там се провали с NoSuchAlgorithmException. Това ме кара да се чудя. Има ли списък с официално поддържани алгоритми? - person tiguchi; 17.11.2012
comment
@Nobu-games Опитвали ли сте кода в тази сигурност. И отговор? - person SquareRootOfTwentyThree; 17.11.2012
comment
В крайна сметка обединих SpongyCastle. По този начин знам, че кодът ми за криптиране ще работи на всяко устройство с Android. Просто ме накара да се притеснявам, че последната официална версия на Android се отърва от нещо, което се съдържа в по-старите (можех да използвам AES/EAX на Samsung Galaxy S с Android 2.3 без проблем). - person tiguchi; 17.11.2012
comment
Благодаря за информативния отговор @SquareRootOfTwentyThree. Имам последващ въпрос: искаме да използваме SHA-256, за да превърнем паролата в AES ключ. За да направя разлика между лоша парола и подправена полезна информация, обмислях да изпратя повторно хеширана парола (т.е. прилагане на SHA-256 към ключа) заедно с полезна информация, така че получателят да може да потвърди, че използва правилната парола. Осъзнавам, че самата преработена парола също може да бъде повредена по време на транзит, така че това вероятно няма да е напълно безупречно. Но въпреки това мислите ли, че това има смисъл? И дали ще бъде безопасно (т.е. не може да се използва)? - person Matthias; 23.11.2012
comment
Що се отнася до режийните, нашите полезни товари ще варират някъде около 1000 и 3000 байта. Толкова доста малък наистина. - person Matthias; 23.11.2012
comment
Не бих използвал SHA2 за извличане на парола. Той е твърде бърз и следователно чувствителен към атаки в речника и дъга. PBKDF2 с произволна сол и достатъчно голям брой итерации е за предпочитане. Мисля, че е добре да вземете получения ключ, да го хеширате (дори с SHA2), за да получите стойност за проверка и да го изпратите (със солта). - person SquareRootOfTwentyThree; 24.11.2012