Як перестати боятися і любити end-to-end шифрування


Привіт, Хабр!
У коментарях до нашого першого посту народ вимагав хліба і видовищ коду і «success story». І якщо з першим у нас все більш-менш нормально, то з другим чогось, якось не складається поки що. Ми, знаєте, люди все молоді, успіхи у нас досить скромні, баскетбол ось непогано граємо. Одним словом, сьогодні ми поки просто трохи покодим і розповімо про реалізацію end-to-end шифрування з використанням наших сервісів. А «success story»? Які наші роки, будуть ще в нашому блозі ці самі success stories.

Керування ключами

Одна з пролем реалізації end-to-end шифрування полягає в безпечної передачі ключів шифрування одержувачу.
Найбільш очевидний спосіб вирішення проблеми — криптографія з відкритим ключем. Кожен користувач системи має ключ, який складається з двох частин: закрита частина (секретний ключ), який зберігається в секреті і ніколи не передається по мережі; відкрита частина (публічний ключ), який повинен бути доступний для всіх учасників системи. Секретний ключ прийнято використовувати для підписання та розшифровки, в той час як за допомогою відкритого ключа здійснюються операції шифрування і перевірки підпису.
Виходячи з визначення секретного і публічного ключа випливає, що абсолютно будь-який учасник системи здатний, використовуючи публічний ключ, зашифрувати повідомлення, але тільки власник секретного ключа здатний розшифрувати це повідомлення.

Перше, що слід взяти до уваги при реалізації схеми з відкритим ключем — це можливість підміни публічного ключа третьою стороною. Зловмисник, який володіє можливістю модифікувати трафік, здатний перехопити публічний ключ користувача Аліса і підмінити його на свій власний публічний ключ. Це призводить до того, що користувач Боб, при спробі відправити зашифраванное повідомлення Алісі, насправді зашифрує його ключем атакуючого, який зможе розшифрувати і прочитати секретні дані.
Один з можливих варіантів запобігання такій ситуації — це можливість однозначно ідентифікувати власника ключа. В такому випадку підміна ключа стане очевидною для Боба. В якості ідентифікатора, можна вказати e-mail адреса, номер телефону та іншу унікальну, але легко распознаваемую інформацію. При цьому слід врахувати, що ідентифікатор указується при створенні нового ключа, повинен бути перевірений і підтверджений. В іншому випадку ми ризикуємо отримати систему, в якій кожен користувач зможе видати себе за кого завгодно.

Для перевірки потрібно імені сервіс перевірки особистості (identity validation service). Як правило, такі сервіси висилають випадково згенерований код на зазначений в якості імені e-mail адресу чи номер телефону і чекають підтвердження від користувача.
Однак використання сервісу перевірки особистості лише перекладає проблему довіри до каналу зв'язку на сам сервіс. Насправді ніщо не заважає власнику сервісу створити ключ скомпрометований, що нібито належить третій стороні.

Для того, щоб повністю позбутися можливості появи скомпрометованих ключів, необхідна автентифікація ключів.
Аутентифікація ключів – спосіб переконати Боба, що ключ, який він вважає належним Алісі, насправді належить Алісі. Існує кілька способів вирішення проблеми ключів аутентифікації. Найбільш очевидний серед них – це обмін ключами при особистій зустрічі або з використанням більш надійного каналу зв'язку. Незважаючи на високу надійність, цей спосіб не завжди реалізуємо в реальному світі. Тому використовується один з наступних методів аутентифікації ключів.
Перший спосіб – використання довірених центрів сертифікації. Коли певний користувач (довірений центр) системи розпорядженні необмеженою довірою і здатний виступати в якості заверителя ключів. Жоден ключ в такій системі не вважається надійним без підпису довіреної центру.
Другий спосіб – використання мережі довіри. При цьому, кожен користувач системи має право підписати ключ будь-якого іншого користувача, підтверджуючи тим самим, що ключ насправді належить вказаному власнику. Чим більше завіряють підписів під ключем, тим більшої довіри заслуговує.

Таким чином, процедура створення, зберігання та передачі ключів має ряд підводних каменів, які легко обійти за допомогою Virgil Security.

Virgil Security

Virgil Security надає набір безкоштовних криптографічних сервісів, використання яких допомагає вирішити безліч проблем, пов'язаних з безпекою. Зокрема, проблему управління ключами.
На сьогоднішній день Virgil Security це:
  1. Virgil crypto library – це оболонка над mbedTLS з відкритим вихідним кодом, яка дозволяє використовувати всі стандартні алгоритми шифрування і підпису. А також додає гібридні алгоритми шифрування (ECIES). Virgil crypto library дозволяє змінювати алгоритми в майбутньому без першифровки існуючих даних — принцип crypto agility.
  2. Virgil identity service – сервіс перевірки особистості з відкритим API, що дозволяє перевірити валідність e-mail адреси. Сервіс висилає на вказаний e-mail секретний код, який повинен бути введений користувачем для підтвердження факту володіння адресою.
  3. Virgil keys service – сервіс публічних ключів, що дозволяє працювати з надійним і доступним сховищем публічних ключів. Кожен ключ у сховищі прив'язаний до спеціальній структурі даних, званої VirgilCard. VirgilCard обов'язково включає в себе: унікальний ідентифікатор карти — id, ідентифікатор власника ключа — e-mail адресу, номер телефону і т. д., а також дату створення ключа. З допомогою Virgil keys service можна швидко знаходити публічні ключі користувачів системи, а також видаляти карти зі скомпрометованими ключами.
  4. Virgil private keys service — сервіс секретних ключів, що відповідає за завантаження, завантаження і видалення секретних ключів. Для доступу до секретного ключа, необхідно підтвердити володіння Virgil картою, до якої він прив'язаний.
Всі перераховані вище сервіси мають широкий вибір готових SDK і можуть використовуватися для вирішення широкого спектру завдань, пов'язаних з інформаційною безпекою.

Virgil services і end-to-end шифрування

Ну ось тепер прийшов час трохи покодить. Покажемо, як за допомогою Virgil Security здійснити надійне end-to-end шифрування. Для цього реалізуємо наступну схему:

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

Для роботи з сервісами Virgil Security нам потрібно отримати секретний токен і пара публічний/закритий ключ. Для цього реєструємося на сайті Virgil Security. Після цього приступаємо до реалізації e2ee.

  1. Викачуємо і встановлюємо VirgilSDK використовуючи NPM:
    npm install virgil-sdk
    

  2. Ініціалізуємо роботу з сервісами Virgil Security:
    var virgil = new VirgilSDK("%ACCESS_TOKEN%");
    

  3. Генеруємо пари ключів:
    var keyPair = virgil.crypto.generateKeyPair();
    
    console.log(keyPair.publicKey);
    console.log(keyPair.privateKey);
    

    І отримуємо ось такий результат: — BEGIN PUBLIC KEY-----
    MFswFQYHKoZIzj0CAQYKKwYBBAGXVQEFaqncaaqo8ohmbryclmcfq38lwmvv4cau
    jyX6vWn8kJrR0RRfFQAAAAAAAAAAAAAAaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    -----END PUBLIC KEY-----

    -----BEGIN EC PRIVATE KEY-----
    MHkCAQEEIFB+lOUvbb4WX+e3zLkAcYpvZR3qpQI8Ru/tcnciCMkIoAwGCisGAQQB
    l1UBBQGhRANCAAQO8ohmBRyclmcfQ38Lwmvv4caujyx6vwn8kjrr0rrffqaaaaaa
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    -----END EC PRIVATE KEY-----

  4. Публікуємо відкритий ключ. Для цього необхідний validation token, що підтверджує особу власника ключа. Отримати validation token можна двома способами: перший скористатися сервісом Virgil Identity, який перевірить дійсно власник ключа має доступ до узаканному email адресу і згенерує validation token. Або можна скористатися приватним ключем додатка і з його допомогою згенерувати validation token самостійно. В такому випадку розробник уникає необхідність довіряти сторонньому сервісу ідентифікації. Скористаємося отриманими validation token і збережемо публічний ключ на сервер:
    var options = {
    public_key: keyPair.publicKey,
    private_key: keyPair.privateKey,
    identity: {
    type: 'member',
    value: 'Darth Vader',
    validation_token: '%VALIDATION_TOKEN%'
    }
    };
    
    virgil.cards.create(options).then(function (card){
    myCard = card;
    console.log(card);
    });
    

    В результаті на сервері публічних ключів буде створена карта наступного виду:
    { 
     
    "id":"3e5a5d8b-e0b9-4be6-aa6b-66e3374c05b3",
     
    "authorized_by":"com.virgilsecurity.twilio-ip-messaging-demo",
     
    "hash":"QiWtZjZyIQhqZK7+3nZmIEWFBU+qI64EzSuqBcY+E7ZtKPwd4ZyU6gdfU/VzbTn6dHtfahCzHasN...",
     
    "data":null,
     
    "created_at":"2016-05-03T14:34:08+0000",
     
    "public_key":{ 
     
    "id":"359abe31-3344-453a-a292-fd98a83e500a",
     
    "public_key":"----- BEGIN PUBLIC KEY-----\nMFswFQYHKoZIzj0CAQYKKwYBBAGXVQEfaqncaaq...",
     
    "created_at":"2016-05-03T14:34:08+0000"
     
    },
     
    "identity":{ 
     
    "id":"965ea277-ab78-442c-93fe-6bf1d70aeb4b",
     
    "type":"member",
     
    "value":"Darth Vader",
     
    "created_at":"2016-05-03T14:34:08+0000"
     
    }
     
    }
     
    



  5. Створюємо канал, по якому будуть передаватися зашифровані повідомлення. Зробити це буде не так складно, як здається. З недавніх пір ми стали партнерами з компанією Twilio, яка зокрема надає API для реалізації IP месенджера. Приклад готового IP месенджера з всроенной функцією end-to-end шифрування можна знайти на тут.
    // Create a Channel
    twilioClient.createChannel({ friendlyName: 'general' }).then(function(channel) {
    generalChannel = channel;
    });
    

  6. Щоб відправити секретне повідомлення знайдемо публічний ключ співрозмовника і скористаємося ним для шифрування:
    // Receive the list of Channel's recipients
    Promise.all(generalChannel.getMembers().map(function(member) {
    // Search for the member's cards on Virgil Keys service
    return virgil.cards.search({ value: member.identity, type: 'member' })
    .then(function(cards){
    return { 
    recipientId: cards[0].id 
    publicKey: cards[0].public_key.public_key
    };
    });
    }).then(function(одержувачі) {
    var message = $('#chat-input').val();
    var encryptedMessage = virgil.crypto.encryptStringToBase64(message, recipients);
    
    generalChannel.sendMessage(encryptedMessage); 
    console.log(encryptedMessage);
    });
    

    Зашифроване повідомлення виглядає наступним чином:
    MIIDBQIBADCCAv4GCSqGSIb3DQEHA6CCau8wgglragecmyicvdccavocaqkgjgqkmdg3yjgwymmtmznjyi00mti1lwi4ytgtyte
     
    3OTEwM2Y3ZjRkMBUGByqGSM49AgEGCisgaqqbl1ubbqeeggeumiibeaibadbbmbugbyqgsm49agegcisgaqqbl1ubbqedqgaecd
     
    8fhKqYlZxvcmmodg7Z3PNhE1LXLJqobouecrfzarmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaybgcogyxxagucm
     
    A0GCWCGSAFlAwQCAgUAMEEwDQYJYIZIAwudbaicbqaemeajmavx7s+52BpI5hYyFOc0noIc+qdFFrQanNAtNGBAX/Pxeg5yJ2iA
     
    JijyZ8ut9zBRMB0GCWCGSAFlAwQBKgQQ81bklcnoyu/QTatCigSzoAQwHnAcbXk0daExIIS+sr6aIvVuF/o6j+1Rs5bvq2WVN41
     
    k/Oir5x7KZTSR7v3nx+fTMIIBWgIBAqAmBCRmNzM4YTUwNi1hMDywltq1mdgtytjkys04njy1njzlyzg0odmwfqyhkozizj0caq
     
    YKKwYBBAGXVQEFAQSCARQwggEQAgEAMFswfqyhkozizj0caqykkwybbagxvqefaqncaarj5c3hsyui2sf14k60dz5mv5yd/AsVA
     
    zPfsmlreGTC2gAAAAAAAAAAAAAAAAAAAaaaaaaaaaaaaaaaaaaaaaaambggbyibjhecbqiwdqyjyiziawudbaicbqawqtanbglg
     
    hkgBZQMEAgIFAAQwhu7WM1rff9RYsQ+dmfX9Os3Irwm4cm5bIvUlcGXlCfmEsrjtytg5mgjyltxbytl9mfewhqyjyiziawudbae
     
    qBBCfKdP/gZnkVwJvv4Hdf2eWBDC3czBjV/yPGeGTqBIilHSsrqwK7lVMTBuKR+mR3eNdh+yBIAcOk4rveSUbDuWagDIwJgYJKo
     
    ZIhvcNAQcBMBkGCWCGSAFlAwQBLgQMfjkcvk3ugxdorcyumtchhusm4yfbacmsnimadaeos7qn7omnsfu1
     
    


  7. Одержувач розшифровує повідомлення, використовуючи секретний ключ:
    // Listen for new Messages sent to a Channel
    generalChannel.on('messageAdded', function(message) {
    
    // Decrypt the Message using card id and private key values.
    var decryptedMessage = virgil.crypto.decryptStringFromBase64(
    message.body, 
    myCard.id 
    keyPair.privateKey
    );
    
    console.log(message.author + ': '+ decryptedMessage);
    });
    

    І побачить наступне:Darth Vader: Luke. I am your father!

Досить просто. Ви пишіть лише кілька рядків коду і отримуєте повноцінне end-to-end шифрування з можливістю ідентифікації і аутентифікації ключів. При цьому сервіси Virgil Security не мають доступу до секретних ключів користувачів, що виключає можливість читання секретних даних.
Джерело: Хабрахабр

0 коментарів

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