<
  • Главная
Статьи

SavePearlHarbor

  1. Вступ
  2. теоретичні відомості
  3. ядро Linux
  4. Userspace
  5. реальний досвід
  6. Мета дослідження
  7. Crypto API
  8. Варіанти стека криптографії на прикладі Openssl
  9. Архітектура soc-aes-accel
  10. продуктивність
  11. Висновок

Нещодавно ми застосували плату   Ethond   в якості міні-роутера і запустили на ньому OpenVPN

Нещодавно ми застосували плату Ethond в якості міні-роутера і запустили на ньому OpenVPN.

Але виявилося, що процесор часто навантажується на 100%, а швидкість не піднімається вище 15-16 Мбіт / с. На каналі зв'язку 100 мегабіт це дуже мало, тому ми вирішили прискорити процес апаратно.

Хлопці з гурту FPGA-розробників зробили прошивку на базі відкритого IP-core для Altera CycloneV з реалізацією шифру AES-128, яка вміє шифрувати 8 Гбіт / сек і дешифрувати 700 Мбіт / сек. Для порівняння, програма openssl на CPU (ARM Cortex A9) того ж CycloneV може обробляти лише близько 160 Мбіт / сек.

Ця стаття присвячена Наш аналіз показує по застосуванню апаратного шифрування AES. Ми стисло представимо опис криптографічного інфраструктури в Linux і опишемо драйвер (вихідний код відкритий і доступний на github ), Який здійснює обмін між FPGA і ядром. Реалізація шифрування на FPGA не є темою статті - ми описуємо лише інтерфейс, з яким відбувається взаємодія c акселератором з боку процесора.

Зараз ми розуміємо, що краще було б спочатку визначити, в чому полягає головний фактор зниження пропускної здатності каналу: раптом насправді не сам процес шифрування, а прохід через програмний стек займає основну частину часу? Ми цього не зробили, і приріст продуктивності в результаті виявився вовсем не таким, як очікувалося. Проте користь все одно є: було цікаво вивчити, як в Linux зареєструвати механізм апаратного прискорення, як до нього можна звернутися з призначених для користувача програм і, нарешті, як змусити популярні речі на зразок openssl і openvpn вибирати прискорений алгоритм, а не стандартний, реалізований програмно.

В майбутньому ми збираємося прискорити саме OpenVPN на Ethond - тоді чекайте від нас чергову статтю!

Вступ

Чим нас так зацікавила криптографія? На перший погляд, вона не йде пліч-о-пліч з обладнанням, яке ми робимо. Однак, застосування для неї ми теж можемо знайти. Величезна частина трафіку зашифрована, і кожен користувач Інтернету регулярно стикається, навіть сам того не знаючи, з криптографією. Наприклад, росте популярність VPN: згідно дослідженню , На початок 2017 року троє людей з десяти використовують цю технологію.

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

За рахунок чого можна домогтися прискорення криптографічних алгоритмів? Якщо їх висловлювати через арифметичні і логічні операції, виходить повільно. У реалізації на спеціалізованих цифрових схемах можна домогтися набагато більшої продуктивності. Хороший набір посилань по темі можна знайти в статті у Вікіпедії про AES instruction set .

Можливо реалізувати алгоритм апаратно на CPU і викликати його виконання через спеціальні інструкції. Відомий приклад - AES-NI від Intel . Однак процесори вбудованих систем часто таким функціоналом не володіють або мають обмеження на експорт / імпорт. В такому випадку можна встановити додаткові периферійні пристрої, які самі будуть обробляти дані. І, звичайно, функціональність такої периферії можна реалізувати і на FPGA.

Вирішивши перевести можливе в реальне, ми почали дослідження апаратного прискорення шифрування на FPGA.

теоретичні відомості

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

ядро Linux

У ядрі Linux реалізовано безліч криптографічних алгоритмів: і симетричні шифри, і хеш-кодування, і режими роботи блокових шифрів. Все це може використовуватися самим ядром: наприклад, для шифрування дисків (dm-crypt) або роботи VPN (IPsec). Забезпеченням уніфікованого доступу до криптографічних функцій займається Kernel CryptoAPI, котрих дозволяє драйверам реєструвати апаратні реалізації відповідних алгоритмів.

Призначені для користувача програми також можуть звертатися до CryptoAPI. Одним з інтерфейсів, що надають таку можливість, є сокет address family AF_ALG і бібліотека-обгортка над ним libkcapi . Основний конкурент AF_ALG - модуль ядра cryptodev (доступ до CryptoAPI через символьне пристрій / dev / crypto).

За словами авторів cryptodev, їх рішення набагато продуктивніше, ніж AF_ALG (див. порівняння ).

На схемі показано CryptoAPI, де зареєстровано дві реалізації AES-128: програмна та апаратна, звернення до якої відбувається через відповідний драйвер.

Здійснити запит до CryptoAPI можуть, наприклад, IPsec, а також модулі af_alg.ko і cryptodev.ko. Обидва дають призначеним для користувача програмам можливість звертатися до криптографічного підсистемі ядра, перший - через сімейство адрес, другий - через символьне пристрій.

Як правило, це виконується прозоро: CryptoAPI саме, отримуючи запит, вибирає, який реалізацією користуватися, однак при бажанні можна дізнатися деякі деталі його роботи через файл / proc / crypto. У ньому задані, зокрема, такі поля:

  • name - назва реалізованого алгоритму.
  • driver - унікальна назва окремої реалізації алгоритму. Ті з них, які закінчуються на -generic, зазвичай є стандартними програмними реалізаціями в ядрі.
  • priority - пріоритет. Якщо у ядра є кілька реалізацій одного і того ж алгоритму, воно обере реалізацію з найвищим пріоритетом. Кожен драйвер сам призначає довільний пріоритет при реєстрації алгоритму. Вибирається реалізація, у якій значення пріоритету найбільше.

Userspace

CryptoAPI, незважаючи на те, що вже є високорівневою абстракцією, має ще одну обгортку: в userspace мало хто звертається до нього безпосередньо і більшість програм за краще використання бібліотек, наприклад, libcrypto і libssl з проекту openssl. Ними користуються, наприклад, openssh, opvenvpn і, цілком очікувано, openssl. Ці бібліотеки підтримують engines, - то, що зазвичай називається плагінами, механізми додавання нових реалізацій алгоритмів криптографії.

Розробниками openssl вже написані engines для шифрування в ядрі через AF_ALG і / dev / crypto. Тому безліч програм автоматично отримують доступ до апаратної реалізації криптоалгоритму, якщо вона зареєстрована в CryptoAPI.

Тому безліч програм автоматично отримують доступ до апаратної реалізації криптоалгоритму, якщо вона зареєстрована в CryptoAPI

На схемі зображено кілька програм, які користуються криптографічними функціями, наданими в бібліотеках libssl і libcrypto, здатних звернутися до CryptoAPI через / dev / crypto або AF_ALG. Наприклад, в libcrypto для того і іншого задані cryptodev engine і afalg engine відповідно.

реальний досвід

Розібравшись з теорією, переходимо до суворої реальності: опису нашого практичного досвіду.

Мета дослідження

При розробці драйвера прискорювача шифрування головний дослідницький питання полягало в тому, яку пропускну здатність між FPGA і призначеними для користувача програмами ми зможемо забезпечити на своїх платах з CycloneV на борту (наприклад, Ethond або BlueSom ). У наших умовах це виявилося важливо: коли шифрування відбувається настільки швидко, основний час витрачається на пересилку даних і синхронізацію відбувається в різних частинах системи.

Наш драйвер практично повністю залежить від того, що нам надає залізо. Тому почнемо з опису апаратної частини.

Тому почнемо з опису апаратної частини

На схемі спрощено показана модель взаємодії процесора та FPGA всередині SoC CycloneV. Для більш точного і докладного опису можна звернутися до оригінального зображення в розділі "Introduction to the Hard Processor" з Cyclone V Device Handbook, Volume 3: Hard Processor Technical Reference Manual , Захоплюючою, але товстої книжки.

Лінукс з нашим драйвером запущений на MPU (Microprocessor Unit) всередині HPS (Hard Processor System). Процесор може звертатися до регістрів FPGA через L3 SWITCH по інтерфейсу HPS-to-FPGA. Звернення до регістрів на схемі зображені блакитними стрілками.

Пристрої, реалізовані в FPGA, можуть звертатися до SDRAM-пам'яті через інтерфейс FPGA-to-HPS по DMA (зелені стрілки), а також надсилати процесору переривання (червоні стрілки). У FPGA реалізовані дві незалежних суті: прискорювач шифрування і прискорювач дешифрування. Кожен з них складається з двох пов'язаних блоків, один з яких реалізує алгоритм (шифрування / дешифрування), а інший обмінюється даними з пам'яттю по DMA.

Кожен з них складається з двох пов'язаних блоків, один з яких реалізує алгоритм (шифрування / дешифрування), а інший обмінюється даними з пам'яттю по DMA

Обидві пари "блоків", реалізованих в FPGA, мають свої регістри.

Encrypt Core і Decrypt Core мають ідентичні набори регістрів, які дозволяють задати ключ (Key), вектор ініціалізації (IV, initialization vector), що використовуються при наступній операції шифрування / дешифрування.

Decrypt DMA і Encrypt DMA також мають дзеркальну структуру. Через їх регістри можна задати адреси і довжини відрізків пам'яті - ці набори параметрів ми названі дескрипторами - в одній частині яких знаходяться вихідні дані, а в іншу потрібно розмістити результат застосування AES. Також доступна можливість включення і виключення переривань для оповіщення про закінчення обробки кожного дескриптора.

Crypto API

Розповімо трохи докладніше про деяких концепціях криптографічного підсистеми Linux.

Однією з її основних сутностей є "транформации" (transformation) - так називаються будь-які перетворення даних: підрахунок хеш-суми, стиснення, шифрування. Драйвер може самостійно "зареєструвати" трансформацію - надати можливість їй користуватися.

Клас типів трансформацій досить великий, однак шифруванням займається лише три їх типи:

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

У CryptoAPI також можна задавати "шаблони" (templates) - реалізації складних сутностей, наприклад, певного режиму роботи блокового шифру або HMAC, на основі простих трансформацій на кшталт шифрування одного блоку даних або підрахунку хеш-суми.

Зокрема, існування шаблонів дозволяє використовувати CRYPTO_ALG_TYPE_CIPHER для реалізації блочного шифру, хоча сама трансформація оперує лише 16-байтовими блоками. Однак це сильно навантажує CPU: ядро ​​саме здійснює управління режимом роботи шифру. Трансформації CRYPTO_ALG_TYPE_BLKCIPHER і CRYPTO_ALG_TYPE_ABLKCIPHER ж беруть це на себе, і ядру не доводиться застосовувати шаблони, що забезпечують режим.

Так як наша прошивка в FPGA зараз реалізує AES-128 в режимі CBC, CRYPTO_ALG_TYPE_CIPHER для нас інтересу не представляє: у нас вже реалізований необхідний режим роботи і з боку процесора не потрібно додаткових витрат.

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

Трансформація віддає CryptoAPI функції для завдання IV (initialization vector), ключа, для шифрування і для дешифрування. Все це вказується драйвером трансформації при її реєстрації в полях структури blkcipher_alg. Так виглядає ця структура :

struct blkcipher_alg {int (* setkey) (struct crypto_tfm * tfm, const u8 * key, unsigned int keylen); int (* encrypt) (struct blkcipher_desc * desc, struct scatterlist * dst, struct scatterlist * src, unsigned int nbytes); int (* decrypt) (struct blkcipher_desc * desc, struct scatterlist * dst, struct scatterlist * src, unsigned int nbytes); const char * geniv; unsigned int min_keysize; unsigned int max_keysize; unsigned int ivsize; };

Розглянемо найцікавіші поля: setkey, callback для установки ключа, і encrypt / decrypt - для шифрування / дешифрування. Структура blkcipher_desc містить в собі IV для операції шифрування. Параметрами src і dst callback'ов encrypt і decrypt задаються області пам'яті, з яких потрібно взяти вихідні дані і в яких треба розмістити результат.

Варіанти стека криптографії на прикладі Openssl

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

Очевидно, що якщо драйвер прискорювача шифрування повинен використовуватися і самим ядром - наприклад, в IPsec - потрібно зареєструвати свою реалізацію в CryptoAPI. У такому випадку доступ до драйвера мають як призначені для користувача програми, так і Linux. Це зазначено на схемі як "Driver option 1".

Однак існує і альтернативна можливість, позначена як "Driver option 2": реалізація свого інтерфейсу для користувача середовища в обхід CryptoAPI і модулів cryptodev і af_alg. Це може здатися неправильним рішенням: рідко відхід від стандартизованих механізмів призводить до приємних результатів. Однак ми ще недостатньо вивчили питання, щоб бути впевненими, що наш випадок добре підходить під CryptoAPI і той не накладає суттєві обмеження на продуктивність.

У поточній реалізації ми вибрали перший варіант, але готові спробувати і другий.

Архітектура soc-aes-accel

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

Ці функції приймають два покажчика на масиви з struct scatterlist. Кожен з них зберігає послідовність областей пам'яті: src - звідки взяти вихідні дані, dst - куди покласти результат. Гарантується, що кожен з таких шматків пам'яті не перетинає кордонів однієї сторінки.

Завдання драйвера виглядає тривіальної:

  1. Відобразити адреси кожної області пам'яті у відповідні їм шинні адреси - ті, за якими пристрій зможе здійснювати звернення по DMA;
  2. Записати шинні адреси і довжини областей пам'яті в регістри DMA-контролера;
  3. Попросити DMA-контролер послати переривання після обробки всіх шматків;
  4. Дочекатися переривання.

Але диявол в деталях: версія DMA-контролера в FPGA, яка у нас реалізована, приймає тільки вхідні дані, які мають розмір, кратний 16 байтам. Скоро це обмеження буде знято, але поки FPGA-розробники не встигають змінити прошивку, ми працюємо з тим, що є: копіюємо мають не кратну 16 байтам довжину шматки пам'яті в послідовний буфер.

продуктивність

Тепер, коли драйвер написаний, потрібно відповісти на животрепетне питання: а наскільки він продуктивний?

Звичайно, можна було б для замірів використовувати openssl, проте ми вирішили написати свою програму openssl_benchmark.c : Openssl не надає нам достатню гнучкість. Зокрема, не можна встановити точний розмір одиночного буфера, який буде надіслано до libcrypto, оскільки openssl може вирішити обробляти вхідні дані по частинах. Також показники продуктивності стає складніше розрізнити, так як витрачається деякий час на введення / висновок, виділення пам'яті, ініціалізацію openssl тощо.

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

За допомогою цієї програми ми шифрували і дешифрували буфери різної довжини (по 1000 операцій обох типів для кожної довжини буфера). Потім порахували пропускну здатність в Мбіт / сек. Все це ми зробили двічі: в першому випадку libcrypto шифрувати наші дані своєї софтової реалізацією ( "Software" на графіках), у другому - віддавала ядру через cryptodev engine ( "Hardware" на графіках).

Все це ми зробили двічі: в першому випадку libcrypto шифрувати наші дані своєї софтової реалізацією ( Software на графіках), у другому - віддавала ядру через cryptodev engine ( Hardware на графіках)

Особливий інтерес представляє момент, в який апаратна реалізація наздоганяє програмну по пропускній здатності. Проведемо вимірювання на меншому проміжку і з меншими інтервалами:

Проведемо вимірювання на меншому проміжку і з меншими інтервалами:

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

З шифруванням на FPGA ситуація складніша. Звернення до librypto передається cryptodev engine, той відкриває / dev / crypto, декількома системними викликами налаштовує сесію для шифрування і тільки потім передає покажчики на буфери для шифрування в модуль cryptodev. Той, в свою чергу, формує у вигляді struct scatterlist * два списки фізичних сторінок, на які спроецирован призначений для користувача буфер в його віртуальному адресному просторі, і передає в CryptoAPI. Наш драйвер має найвищий пріоритет з усіх зареєстрованих реалізацій AES, тому списки отримує він. Коли драйвер переконується в тому, що довжини всіх шматків пам'яті кратні довжині блоку AES, він отримує відповідні шинні адреси і записує їх в регістри FPGA.

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

Читач, який подивиться не тільки на форму ліній, але і на конкретні числові значення, звичайно, здивується: чому дешифрування стабілізується на 250 Мбіт / с, а шифрування - на 400 Мбіт / с? Насправді драйвер тут абсолютно ні при чому, так відбувається тому, що в FPGA, незважаючи на дзеркальний інтерфейс, процедури шифрування і дешифрування реалізовані по-різному.

З'ясуємо тепер, наскільки навантажується CPU при використанні апаратного шифрування. З навантаженням на CPU при роботі програмної реалізації шифрування все і так очевидно: CPU повинен використовуватися на сто відсотків, так як саме він є вузьким місцем. Побіжна перевірка показує, що так і є.

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

Ось отримані результати:

Розмір буфера 16 256 1024 4096 8192 450000 Шифрування 92% 89% 81% 63% 53% 29% Дешифрування 93% 91% 86% 74% 64% 43%

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

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

Висновок

Між молотом FPGA і ковадлом програм в просторі користувача живеться на подив непросто. Основна проблема в положенні драйвера полягає в дуже високих вимогах до швидкості обміну: лише на великих обсягах даних стає помітною перевага апаратної реалізації. Занадто багато часу витрачається на проходження запиту через весь стек. Однак починаючи з деякого обсягу апаратна реалізація істотно знімає навантаження з процесора і стає швидше програмної в півтора-два рази.

посилання на оригінал статті https://habrahabr.ru/post/324042/

За рахунок чого можна домогтися прискорення криптографічних алгоритмів?
Читач, який подивиться не тільки на форму ліній, але і на конкретні числові значення, звичайно, здивується: чому дешифрування стабілізується на 250 Мбіт / с, а шифрування - на 400 Мбіт / с?


Новости
  • Виртуальный хостинг

    Виртуальный хостинг. Возможности сервера распределяются в равной мере между всеми... 
    Читать полностью

  • Редизайн сайта

    Редизайн сайта – это полное либо частичное обновление дизайна существующего сайта.... 
    Читать полностью

  • Консалтинг, услуги контент-менеджера

    Сопровождение любых интернет ресурсов;- Знание HTML и CSS- Поиск и обновление контента;-... 
    Читать полностью

  • Трафик из соцсетей

    Сравнительно дешевый способ по сравнению с поисковым и контекстным видами раскрутки... 
    Читать полностью

  • Поисковая оптимизация

    Поисковая оптимизация (англ. search engine optimization, SEO) — поднятие позиций сайта в результатах... 
    Читать полностью