Криптографія для розробників: Chapter: 4
Вітаю товариство! Сьогодні ми продовжимо з вами розмову про криптографію для розробників. А саме поговоримо про цифровий підпис в Node.js та поняття Trust.
Cписок наступних частин публікацій і попередніх:
- Криптографія для розробників: Chapter 1
- Криптографія для розробників: Chapter 2
- Криптографія для розробників: Chapter: 3
Перелік властивостей цифрового підпису
Цифрові підписи мають кілька основних властивостей, які роблять їх наріжним каменем безпечного зв’язку та обміну даними в цифровому світі.
Основними властивостями цифрового підпису є:
- Автентичність: цифрові підписи підтверджують особу відправника повідомлення або підписувача документа. Використовуючи криптографію з відкритим ключем, одержувач може перевірити особу відправника за допомогою свого відкритого ключа та переконатися, що повідомлення було надіслано або документ підписаний заявленою особою.
- Цілісність: цифрові підписи забезпечують цілісність переданих даних. Оскільки підпис походить із самого повідомлення, будь-яка зміна повідомлення (навіть незначна) призведе до недійсності цифрового підпису. Одержувачі можуть перевірити, чи було повідомлення підроблено під час передачі, порівнюючи підпис із нещодавно обчисленим хешем отриманого повідомлення.
- Невідмовність: цифрові підписи забезпечують невідмовність, тобто підписувач не може пізніше заперечити, що підписав повідомлення чи документ. Оскільки цифровий підпис унікально генерується за допомогою закритого ключа підписувача, можна довести, що підпис був створений заявленим підписувачем, і він не може відмовитися від своїх дій.
- Неможливість підробити: цифрові підписи неможливо підробити через природу криптографічних алгоритмів. Для зловмисника неможливо підробити дійсний цифровий підпис без доступу до закритого ключа підписувача.
- Неможливість підробити: цифрові підписи неможливо підробити через природу криптографічних алгоритмів. Для зловмисника неможливо підробити дійсний цифровий підпис без доступу до закритого ключа підписувача.
- Можливість перевірки: будь-яка третя сторона, яка володіє відкритим ключем підписувача, може перевірити цифровий підпис. Це дозволяє незалежно перевіряти правдивість і цілісність даних, забезпечуючи довіру в процесі спілкування.
- Можливість передачі: цифрові підписи можна передавати, тобто ними можна ділитися з іншими для перевірки автентичності та цілісності повідомлення. Це дозволяє багатьом сторонам довіряти та перевіряти підписані дані.
Принцип роботи цифрового ключа
Цифровий підпис працює на основі криптографічних методів, що використовують систему публічного і приватного ключів для перевірки автентичності відправника та забезпечення цілісності даних під час передачі.
Основна ідея роботи цифрового підпису полягає в наступних кроках:
1. Генерація ключів: Відправник генерує пару ключів — приватний та публічний. Приватний ключ залишається в таємниці у відправника, а публічний ключ передається одержувачу.
2. Хешування повідомлення: Відправник створює хеш повідомлення — унікальне компактне представлення повідомлення. Це забезпечує цілісність переданих даних. Зазвичай використовуються такі алгоритми хешування, як SHA-256 або SHA-3.
3. Підписання повідомлення: Відправник генерує цифровий підпис, шифруючи хеш повідомлення своїм приватним ключем. Цифровий підпис надсилається разом з оригінальним повідомленням до одержувача.
4. Перевірка підпису: Одержувач розшифровує цифровий підпис, використовуючи публічний ключ відправника, і порівнює отриманий хеш повідомлення з хешем отриманого повідомлення. Якщо розшифрований хеш та обчислений хеш збігається, підпис вважається автентичним, що забезпечує цілісність та автентичність даних.
У результаті цифрові підписи дозволяють перевірити автентичність відправника, забезпечити не можливість відмови від підписання та гарантувати цілісність даних в онлайн-світи.
Як розробники використовують цифровий підпис?
Розглянемо простий приклад, з яким всі стикають, а саме GIT. Він надає нам можливість додати цифровий підпис до кожного коміту, який ми створюємо, використовуючи при цьому GPG стандарт.
GPG — це інструмент, що дозволяє безпечно шифрувати та передавати повідомлення, файли, використовуючи криптографічні протоколи шифрування з відкритим ключем. Даний інструмент базується на стандарті RFC4880 та підтримує різні алгоритми шифрування та хешування, але в даній публікації нам важливий RSA тому зупинимося на ньому.
Якщо ви пам’ятаєте, перед тим як створити коміт вперше ви вказуєте user.name та user.email і ми можемо туди вписати що забажає, тому це не дає гарантії того, що це наш власний коміт. Тому що інший учасник, який має доступ до репозиторію, може спокійно поміняти свої дані на наші й виглядатиме, що коміт, який був ним створений є нашим. Тому, щоб убезпечити розробку, якогось чутливого коду, якщо так можна сказати, ми повинні налаштувати обов’язковий підпис для кожного учасника репозиторію. Так ми точно можемо бути певні, що коміт був зроблений від конкретного учасника.
Більш детально можете прочитати тут
Я думаю теорії на цю мить вистачить, перейдімо до практичного прикладу.
Створення і підтвердження підпису за допомогою Node.js
Приклад на основі RSA
const crypto = require("crypto");
// Generate a key pair.
crypto.generateKeyPair("rsa", {
modulusLength: 2048,
publicKeyEncoding: {
type: "spki",
format: "pem",
},
privateKeyEncoding: {
type: "pkcs8",
format: "pem",
},
}, (err, publicKey, privateKey) => {
if (err) {
console.error("Error generating key pair:", err);
return;
}
// Sign data using the private key.
const sign = crypto.createSign("SHA256");
const data = "Hello, Digital Signature!";
sign.write(data);
sign.end();
const signature = sign.sign(privateKey, "base64");
console.log("Data:", data);
console.log("Signature:", signature);
// Verify the signature using the public key.
const verify = crypto.createVerify("SHA256");
verify.write(data);
verify.end();
const result = verify.verify(publicKey, signature, "base64");
console.log("Verification result:", result);
});
// Generate a key pair.
crypto.generateKeyPair("rsa", {
modulusLength: 2048,
publicKeyEncoding: {
type: "spki",
format: "pem",
},
privateKeyEncoding: {
type: "pkcs8",
format: "pem",
},
}, (err, publicKey, privateKey) => {
if (err) {
console.error("Error generating key pair:", err);
return;
}
// Sign data using the private key.
const sign = crypto.createSign("SHA256");
const data = "Hello, Digital Signature!";
sign.write(data);
sign.end();
const signature = sign.sign(privateKey, "base64");
console.log("Data:", data);
console.log("Signature:", signature);
// Verify the signature using the public key.
const verify = crypto.createVerify("SHA256");
verify.write(data);
verify.end();
const result = verify.verify(publicKey, signature, "base64");
console.log("Verification result:", result);
});
У цьому прикладі ми створюємо пару ключів RSA та використовуємо її для підпису даних. Потім отриманий підпис перевіряється за допомогою відкритого ключа.
Data: Hello, Digital Signature!
Signature: iiMIbONb/ZmQk+wmbh3dXyu7LeZDPplypsQveOqB47DTiT0vb9Cov27ex6DTHMmtvzQP2Xdn0/RtpcznGndD31f8FkEVtz6Nk9md61QY2CBjiN8Na1lpadqPZBGjoZ/39VzWWHkwzocEiQwhS9aNH83q1Az1c6FRudrNJWGRBUfy1OmPjXcZBrlTPAFI9sKwpzcvSqmIBQiiWTLopWP1/FT7jQI9tKMVAMamVKkDC+w0Rv+3KcvHldVmBg96T2XNwyZrwQy/Y0amJzBupefmn9hv6OLUCT2kcMRbBENMlUoZrfK2yUzM9rAFjsXFteiwasfXyREt7nlPZ97Gad3s9Q==
Verification result: true
Також ми з вами розглянемо приклад на основі Elliptic Curves
Криптографія еліптичної кривої пропонує кілька переваг перед RSA.
Генерація ключів відбувається швидше, а з меншими розмірами ключів ECC забезпечує подібну або кращу безпеку порівняно з RSA. Це особливо важливо для обмежених пристроїв і в середовищах з низькою пропускною здатністю.
const crypto = require("crypto");// Generate an EC key pair with the P-256 curve.
crypto.generateKeyPair("ec", {
namedCurve: "prime256v1", // secp256r1, also known as P-256
publicKeyEncoding: {
type: "spki",
format: "pem",
},
privateKeyEncoding: {
type: "pkcs8",
format: "pem",
},
}, (err, publicKey, privateKey) => {
if (err) {
console.error("Error generating key pair:", err);
return;
}
// Sign data using the private key.
const sign = crypto.createSign("SHA256");
const data = "Hello, ECC Digital Signature!";
sign.write(data);
sign.end();
const signature = sign.sign(privateKey, "base64");
console.log("Data:", data);
console.log("Signature:", signature);
// Verify the signature using the public key.
const verify = crypto.createVerify("SHA256");
verify.write(data);
verify.end();
const result = verify.verify(publicKey, signature, "base64");
console.log("Verification result:", result);
});
Data: Hello, ECC Digital Signature!
Signature: MEUCIQCbhz9UIaP1a5Euf9gjyYk8vB9iPzpmoeeYqc48C1vOJgIgHzJEk2UavYP/zyPqU5gZL7hfeSo3Xx07R+dd32Objic=
Verification result: true
В даному прикладі ми робимо теж саме, що і в попереднього, просто використовуючи ECC.
Проблема Trust keys(ключів довіри)
Проблема довіри до ключів стосується завдання переконатися, що відкритий ключ справді належить заявленому власнику. У криптосистемі з відкритим ключем користувач створює пару ключів, що складається з закритого ключа (який зберігається в таємниці) і відкритого ключа (який використовується спільно з іншими). Ці ключі використовуються для кількох криптографічних операцій, таких як шифрування, дешифрування та перевірка цифрового підпису. Щоб довіряти відкритому ключу, ви повинні бути впевнені, що пара ключів не була підроблена або змінена зловмисниками.
Є кілька проблем і ризиків безпеки, пов’язаних із довірою ключів:
- Атака “людина посередині” (MITM): під час обміну відкритими ключами зловмисна третя сторона може перехопити зв’язок і замінити свій власний відкритий ключ на законний. Це дозволить зловмиснику видати себе за сторони, що спілкуються, і потенційно розшифрувати або підробити повідомлення.
- Підробка або видавання себе за іншу особу: зловмисник може створити підробку з відкритим ключем іншого користувача та стверджувати, що він є його власним. Це може призвести до несанкціонованого доступу та зловживання даними.
- Зламаний приватний ключ: якщо приватний ключ користувача зламано, зловмисник може видати себе за користувача та виконати операції цифрового підпису від його імені.
- Управління ключами: належне керування парами ключів вимагає ретельного розгляду, включаючи зберігання ключів, безпечне розповсюдження відкритих ключів і безпечне видалення ключів, які більше не потрібні або були скомпрометовані.
Для розв’язання проблеми довіри до ключів можна використовувати кілька підходів:
- Інфраструктура відкритих ключів (PKI): PKI — це система, яка використовує цифрові сертифікати та довірені центри сертифікації (CA) для керування та перевірки автентичності відкритих ключів. Користувачі отримують цифровий сертифікат, підписаний довіреним центром сертифікації, який підтверджує автентичність їх відкритого ключа. Отримавши відкритий ключ, користувачі можуть перевірити сертифікат, щоб підтвердити, що відкритий ключ справжній.
- Мережа довіри: децентралізована схема, така як мережа довіри, що використовується PGP (Pretty Good Privacy), дозволяє користувачам підписувати відкриті ключі один одного, щоб підтвердити свою надійність. Встановивши ланцюжок довіри, користувачі можуть перевірити справжність відкритих ключів на основі підписів ключів, створених іншими довіреними користувачами в мережі.
- Довіра при першому використанні (TOFU): у цій моделі користувач приймає відкритий ключ, коли отримує його вперше, а подальші повідомлення порівнюються з оригінальним ключем. Цей підхід використовується SSH (Secure Shell), але він вразливий до атак MITM під час початкового обміну ключами.
- Протоколи безпечного обміну ключами. Криптографічні протоколи, як-от Діффі-Хеллмана, надають способи безпечного обміну ключами та встановлення безпечного каналу зв’язку через незахищену мережу.
Важливо ретельно керувати відкритими ключами та перевіряти їх, щоб підтримувати безпечне спілкування між користувачами. Вибір методів довіри ключам залежить від конкретних вимог, ризиків і обмежень кожної ситуації.