Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що таке симетричний і асиметричний ключ в шифруванні?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Симетричне шифрування** використовує один спільний ключ і для шифрування, і для дешифрування. **Асиметричне шифрування** використовує пару ключів: публічний шифрує, приватний дешифрує. Симетричне швидше; асиметричне вирішує проблему розподілу ключів. Більшість систем поєднують обидва: асиметричне для рукостискання, симетричне для даних.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Симетричне шифрування** використовує один спільний секретний ключ і для шифрування, і для дешифрування даних. Асиметричне шифрування використовує пару ключів: публічний шифрує, приватний дешифрує. ## Теорія ### TL;DR - Симетричне - це ніби скринька з одним ключем, яким поділилися обидві сторони; асиметричне - поштова скринька, куди всі кидають листи (публічний ключ), але відкрити її можеш тільки ти (приватний ключ). - Головна різниця: симетричне швидке, але обидві сторони мусять заздалегідь отримати один ключ; асиметричне вирішує цю проблему, але дорожче по CPU. - Великі обсяги даних: симетричне (AES). Обмін ключем через ненадійний канал: асиметричне (RSA). - AES - стандарт для симетричного шифрування; RSA і ECC - для асиметричного. ### Швидкий приклад ```python from cryptography.fernet import Fernet # Симетричне: один ключ для обох операцій key = Fernet.generate_key() # Цей ключ має залишатися секретним cipher = Fernet(key) encrypted = cipher.encrypt(b"Secret message") decrypted = cipher.decrypt(encrypted) print(decrypted) # b'Secret message' # encrypt() і decrypt() використовують той самий ключ ``` Один і той самий `key` виконує обидві операції. У цьому вся суть симетричного шифрування. Проблема виникає тоді, коли цей ключ треба безпечно передати іншій стороні. ### Головна різниця При симетричному шифруванні обидві сторони мусять мати однаковий ключ ще до початку спілкування. Якщо цей ключ пройде через відкритий канал, той хто перехопить його прочитає все. Асиметричне шифрування обходить цю проблему: публічний ключ можна передавати відкрито, він тільки шифрує. Для дешифрування потрібен приватний ключ, який ніколи не покидає власника. Платиш за це швидкодією. RSA використовує модульне піднесення до степеня на великих числах, що приблизно в 100-1000 разів повільніше за операції AES. На практиці це не вибір між двома підходами, а їх комбінування: TLS, PGP і SSH використовують асиметричне шифрування щоб встановити сесію, а симетричне - щоб передавати дані. ### Коли що використовувати - Шифрування файлів, стовпців БД, дисків: симетричне (AES-256). - Передати секрет людині через ненадійний канал: асиметричне (RSA доставляє ключ). - TLS-рукостискання (handshake): асиметричне для початкового обміну ключем, симетричне для сесії. - Цифрові підписи і підтвердження авторства: асиметричне (приватний ключ підписує, публічний перевіряє). - Потокове шифрування великих обсягів або локальне шифрування: тільки симетричне. ### Таблиця порівняння | Аспект | Симетричне (AES) | Асиметричне (RSA) | |---|---|---| | Ключі | 1 спільний ключ | Пара: публічний + приватний | | Швидкість | Швидке (апаратне прискорення AES-NI) | Повільне (важкі математичні операції) | | Розмір ключа | 128-256 біт | 2048+ біт | | Розподіл ключів | Ризикований через відкриті канали | Публічний ключ безпечно передавати | | Застосування | Масиви даних, шифрування дисків | Обмін ключами, підписи | | Приклади алгоритмів | AES, ChaCha20 | RSA, ECC, Diffie-Hellman | ### Як це працює всередині AES обробляє 128-бітові блоки через 10-14 раундів підстановок і перестановок. Сучасні CPU виконують це апаратно через AES-NI, тому навантаження мінімальне. RSA працює інакше: шифрування - це `c = m^e mod n` за публічним показником і модулем; дешифрування - `m = c^d mod n` за приватним показником. Саме модульне піднесення до степеня на 2048-бітних числах і є дорогою частиною. Детальніше про те, [як влаштована пара публічний/приватний ключ](/interview-qa/what-is-private-and-public-keys), читай в окремій статті. ### Типові помилки **Передавати симетричний ключ у відкритому вигляді.** ```python # Неправильно key = b'my-secret-key-123' send_over_http(key) # Хто слухає мережу, отримає ключ ``` Рішення: передавати ключ через асиметричне шифрування або делегувати це сервісу управління ключами (AWS KMS, HashiCorp Vault). **Повторне використання IV у AES-CBC.** ```python # Неправильно: той самий IV для кожного повідомлення iv = b'fixed-iv-1234567' cipher1 = AES.new(key, AES.MODE_CBC, iv) cipher2 = AES.new(key, AES.MODE_CBC, iv) # Однакові тексти = однакові шифротексти ``` NIST забороняє повторне використання IV. Генеруй новий випадковий IV для кожного повідомлення і передавай його разом з шифротекстом. **RSA з ключем 1024 біт.** Такі ключі вже розкривали на обладнанні 2023 року. Мінімум - 2048 біт, або перейди на ECC (256 біт дають еквівалентний захист при меншому навантаженні на CPU). **Симетричне шифрування без автентифікації.** AES-CBC сам по собі не підтверджує, хто надіслав повідомлення. Додай HMAC або перейди на AES-GCM, який включає автентифікацію без додаткових кроків. ### Де зустрічається в реальному коді - TLS 1.3: RSA/ECDH для рукостискання, AES-256-GCM для сесії. - AWS KMS: RSA обгортає AES-ключ для кожного запиту (гібридна модель). - PostgreSQL `pgcrypto`: AES для шифрування окремих стовпців. - Node.js: `crypto.createCipheriv('aes-256-gcm', key, iv)` для API-запитів. - PGP: RSA шифрує AES-ключ сесії, AES шифрує тіло повідомлення. ### Питання на співбесіді **Q:** Чому TLS використовує і симетричне, і асиметричне шифрування? **A:** Асиметричне потрібне для початкового рукостискання, щоб безпечно обмінятися сесійним ключем. Далі в роботу йде симетричне (AES-GCM), бо воно набагато швидше. **Q:** Що таке Diffie-Hellman і як він пов'язаний з цим? **A:** Це протокол погодження ключів, який дозволяє двом сторонам вивести спільний симетричний ключ, не передаючи його напряму. TLS 1.3 використовує ECDHE - варіант на еліптичних кривих. **Q:** В чому різниця між AES-CBC і AES-GCM? **A:** CBC тільки шифрує; для перевірки цілісності потрібен окремий HMAC. GCM поєднує шифрування і автентифікацію в одному кроці. Зараз стандартом є GCM. **Q (senior):** Поясни атаку padding oracle на AES-CBC і як від неї захиститися. **A:** Зловмисник надсилає модифіковані шифротексти і читає відповіді сервера. Різниця між повідомленнями про помилку padding і помилку дешифрування дозволяє розшифровувати дані байт за байтом без ключа. Захист: використовувати AES-GCM, або щонайменше encrypt-then-MAC, щоб виявляти будь-яку зміну до запуску дешифрування. ## Приклади ### Node.js: обмін ключем за схемою HTTPS Цей патерн повторює те, що TLS робить під час рукостискання: RSA захищає передачу ключа, AES обробляє дані. ```javascript const crypto = require('crypto'); // Сервер генерує RSA-пару const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', { modulusLength: 2048 }); // Клієнт генерує AES-ключ і шифрує його публічним ключем сервера const aesKey = crypto.randomBytes(32); const encryptedKey = crypto.publicEncrypt(publicKey, aesKey); // Сервер розшифровує приватним ключем; тепер обидві сторони мають aesKey const decryptedKey = crypto.privateDecrypt(privateKey, encryptedKey); console.log(Buffer.compare(aesKey, decryptedKey) === 0); // true // Далі обидві сторони використовують aesKey для швидкого симетричного шифрування ``` RSA не може напряму шифрувати великі дані (ліміт для 2048-бітного RSA - близько 245 байт). Тому ним шифрують тільки ключ, а не самі дані. ### Python: гібридне шифрування для великих даних RSA шифрує AES-ключ. AES шифрує самі дані. Цей патерн називається гібридним шифруванням (hybrid encryption) - саме так влаштовані PGP і TLS всередині. ```python from cryptography.hazmat.primitives.asymmetric import rsa, padding from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes import os # Генеруємо RSA-пару private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048) public_key = private_key.public_key() # Генеруємо AES-ключ сесії aes_key = os.urandom(32) iv = os.urandom(16) # Шифруємо дані через AES data = b"Large payload " * 100 cipher = Cipher(algorithms.AES(aes_key), modes.CBC(iv)) enc = cipher.encryptor() ciphertext = enc.update(data) + enc.finalize() # Шифруємо AES-ключ через RSA (можна передавати разом з шифротекстом) wrapped_key = public_key.encrypt( aes_key, padding.OAEP(mgf=padding.MGF1(hashes.SHA256()), algorithm=hashes.SHA256(), label=None) ) # Отримувач: розшифровує AES-ключ через RSA, потім дані через AES unwrapped_key = private_key.decrypt( wrapped_key, padding.OAEP(mgf=padding.MGF1(hashes.SHA256()), algorithm=hashes.SHA256(), label=None) ) dec_cipher = Cipher(algorithms.AES(unwrapped_key), modes.CBC(iv)) dec = dec_cipher.decryptor() print(dec.update(ciphertext) + dec.finalize() == data) # True ``` AES-ключ займає 32 байти - добре вкладається в ліміт RSA. Самі дані проходять повз RSA повністю. Саме тому і існує гібридне шифрування.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.