image

У каждого есть свои тайны и человечество вечно пыталось находить пути как их скрытия так и разоблачения.


Под катом будет описан один из способов скрыть свои файлы так, чтобы ваш параноик был счастлив


Не могу сказать, что я параноик до мозга костей, но бывают случаи когда мне нужно быть уверенным, что информация не попадет куда не надо, но при этом и не потеряется.


Хочу заметить, что я не претендую на звание "уникальный проект", есть 100500 похожих проектов со своими плюсами и минусами.


Краткое описание


Как видно из названия, dropcryptbox работает поверх dropbox используя oauth. Все операции происходят исключительно между машиной пользователя и api дропбокса минуя третьих посредников, а это значит, что приложение не имеет своего бекенда.


Файлы шифруются и расшифровываются на машине пользователя тем самым гарантируя, что оригинальный файл не попадет на какие-либо сервера.


Генерация ключа


Ключ шифрования создается на основе мастер пароля который нужно ввести при открытии страницы. Для начала получаем sha256 хеш от masterPassword, затем генерируем pbkdf2 ключ на основе полученного хеша(sha256), pbkdf2 (HMAC-SHA1, 256 бит, 1000 итераций)


Код
import sha256 from "crypto-js/sha256";
import pbkdf2 from "crypto-js/pbkdf2";
import HEX_ENCODING from "crypto-js/enc-hex";

export const PBKDF2 = pbkdf2;
export const SHA256 = sha256;

export const salt = SHA256("CRYPTODROPBOX_SOME_SALT");

export function getKey(str){
    let hash = PBKDF2(SHA256(str), salt, { keySize: 256/32, iterations: 1000 });
    return new Buffer(hash.toString(HEX_ENCODING), 'hex');
}

Шифрование файлов


Для шифрования файлов используется chacha20.


Всё шифрование в приложении происходит по алгоритму:


  • Генерируется рандомный nonce
  • Шифрование на основе полученного ключа(от мастер пароля)
  • nonce добавляется в начало шифротекста

Имя файла также шифруется по алгоритму выше, результат преобразовывается в hex и добавляется окончание .ar


Код
import chachaAsync from './chacha20'; // расширенная версия chacha для получение прогресса шифрования
import chacha from 'chacha20';
import { sync as randomBytesSync } from 'random-bytes';

export const NONCE_SIZE = 8;
export const KEY_SIZE = 32;

export function generateNonce(){
    return randomBytesSync(NONCE_SIZE);
}

export function encrypt(buffer, key, nonce, options = {}){
    let encrypted = chacha.encrypt(key, nonce, buffer);
    if(options.joinNonce)
        encrypted = Buffer.concat([nonce, encrypted]);

    return encrypted;
}

export function decrypt(buffer, key, nonce){
    return chacha.decrypt(key, nonce, buffer);
}

export function createEncryptJob(buffer, key, nonce){
    return chachaAsync.encrypt(buffer, key, nonce);
}

export function createDecryptJob(buffer, key, nonce){
    return chachaAsync.decrypt(buffer, key, nonce);
}

Детали


Для ui используется react + redux, webpack, es6 + es7 decorators. Чтобы не нагружать основной поток — отправка, скачивание, шифрование и расшифровка файлов выполняются в отдельном потоке (webworkers).


На данный момент поддерживаются только новейшие версии firefox и chrome


Демо. Совсем скоро код будет размещен на GitHub.

Поделиться с друзьями
-->

Комментарии (27)


  1. rhamdeew
    05.01.2017 15:10
    +6

    Интересный вариант. Лично я поступил по-другому. Создал encfs-раздел на локальной системе. В Dropbox положил зашифрованный каталог. В итоге получается что в сторадже есть и обычные нешифрованные файлы и папка с "кракозябрами"


    1. darken99
      05.01.2017 18:44
      +1

      Плюс есть куча клиентов для всех платформ.
      Сам использую этот вариант.


      1. Goodkat
        05.01.2017 20:03

        А не подскажете удобный клиент для iOS?
        Я пользуюсь старым приложением Boxcryptor, которое не обновлялось уже три года, и, боюсь, может в любой момент перестать работать или вылететь из App Store, так как разработчик продвигает новое приложение, которое работает иначе.


        1. darken99
          05.01.2017 20:37

          Я пользуюсь KeePass Touch


          1. Goodkat
            05.01.2017 20:55
            +1

            Мы точно говорим о файловом менеджере, работающим с Dropbox и поддерживающим шифрованную файловую систему encfs, о которой написал rhamdeew в комментарии выше?

            Судя по описанию, KeePass Touch — это менеджер паролей.


            1. darken99
              06.01.2017 01:28
              +1

              Извиняюсь, использую BoxCryptor


  1. EvilGenius18
    05.01.2017 15:15
    +1

    А почему решили делать эксклюзивно для дропбокс?

    Не легче ли просто зашифрованные файлы ложить в папку синхронизации на пк, которые потом уже в шифрованном виде отгружаются на дропбокс?

    Таким образом можно было бы использовать для всех облачных хранилищ одновременно


    1. kwolfy
      05.01.2017 15:22

      Была цель реализовать проект насколько возможно быстро — поэтому dropbox

      Ваш вариант тоже интересен, но у меня есть много идей которые требуют взаимодействия с именно файловым сервером, а не локальной папкой


  1. ooprizrakoo
    05.01.2017 17:06
    +2

    Дядь, а дядь. Ну подумай немножко шире, как твой пост выглядит в хабраленте?

    imageта


    1. ooprizrakoo
      05.01.2017 17:18
      +1

      Спасибо :)


  1. Scratch
    05.01.2017 17:13

    Шифровать все файлы одним ключом нехорошо. Лучше генерируйте рандомный chacha ключ (надеюсь, там poly1305 используется? ) для каждого файла и уже его шифруйте своим мастер ключом из KDF. А потом пишите его вначало файла.

    Без HMAC типа poly1305 любой файл можно поменять и вы этого не поймете при расшифровке. Зашифрованный ключ файла можно добавить в additional data режима AEAD, если используете chacha20-poly1305.


    1. kwolfy
      05.01.2017 17:17

      Используется chacha20-poly1305.
      В чём принципиальная разница между тем шифровать всё одним ключем или разными ключами когда у нас и так есть уникальный nonce?


      1. Scratch
        05.01.2017 17:30

        гипотетически расшифровав один файл, мы не сможем расшифровать остальные


        1. kwolfy
          05.01.2017 17:32

          Гипотетически эту проблему решает как раз nonce


          1. Scratch
            05.01.2017 17:37
            -1

            Как скажете ) Ваш же продукт


  1. agee
    05.01.2017 20:06
    +2

    О хорошем: во-первых, спасибо за работу :)


    Теперь о замечаниях, не посчитайте за придирки. Статья для крипто-темы оочень маленькая.


    0) Исходный код.
    1)


    не претендую на звание "уникальный проект", есть 100500 похожих проектов со своими плюсами и минусами

    Вот эту часть как раз таки нужно подробно описать. Примеры готовых решений? Чем они не устроили? Чем Ваше решение лучше или хотя бы не хуже существующих?


    2) Описание схемы шифрования не должно быть ограничено одним предложением. Из него совсем не понятно, насколько глубоко Вы владеете темой. Я вот, например, с поточными шифрами не работал. Чего там происходит вообще? Я имею в виду сам процесс, это же самое важное и интересное.


    3) Каков сам процесс расшифровки, вообще не понятно. Почему выбран поточный шифр? Данные расшифровываются на лету? Если да, то этого никак не понять из статьи (ну может, я не углядел). Если нет, то почему не блочный шифр?


    export function encrypt(buffer, key, nonce, options = {})


    Что там в качестве буфера передается?


    4) Там в коде какие-то импорты из "crypto-js". Это какая-то библиотека? Почему ей можно доверять?


    5) Ни слова о MAC. Приходится из комментариев вылавливать, что используется poly1305. В коде не видно этого :(


    6)
    export const salt = SHA256("CRYPTODROPBOX_SOME_SALT");


    У Вас константная соль? Какой в ней смысл вообще? Смотрю https://www.ietf.org/rfc/rfc2898.txt и максимум, что приходит на ум это часть


    If a random number generator or pseudorandom generator is not
    available, a deterministic alternative for generating the salt (or
    the random part of it) is to apply a password-based key derivation
    function to the password and the message M to be processed. For
    instance, the salt could be computed with a key derivation function
    as S = KDF (P, M). This approach is not recommended if the message M
    is known to belong to a small message space (e.g., "Yes" or "No"),
    however, since then there will only be a small number of possible
    salts.

    В остальных случаях она вообще случайная должна быть. Доступ к PRNG вроде есть. (import { sync as randomBytesSync } from 'random-bytes';-bytes';)


    7)
    В коде
    let hash = PBKDF2(SHA256(str), salt, { keySize: 256/32, iterations: 1000 });
    В чем смысл шага SHA256(str)?


    1. kwolfy
      06.01.2017 18:34

      Спасибо за здоровую критику.

      Вообще всё это тема для следующей статьи, а сейчас отвечу кратно на некоторые вопросы.

      1. На данный момент никаких преимуществ нет, но скоро будут новые функции которые раскроют подробнее эту тему

      2,3. Поточный шифр только из соображений производительности т.к. на данный момент chacha20 работает быстрее aes, но в будущем расшифровка на лету тоже не исключение

      4. crypto-js — это самая популярная браузерная криптобиблиотека на данный момент, причина доверять ей — открытый код

      5. Статья писалась за час и была сразу опубликована, изначально расчет идет на более глубокое продолжение, помилуйте, не могу же я раскрыть все свои темы в одной статье))

      6,7. Смысл sha256 — усложнение перебора, хоть и сомнительная операция. Константная соль, потому что в следующей версии планируется вообще заменить pbkdf2 на scrypt


      1. agee
        07.01.2017 04:12

        Переход на scrypt не отменяет генерации рэндомной соли. Кстати, scrypt внутри себя использует pbkdf2))

        https://tools.ietf.org/html/rfc7914#page-3


        1. kwolfy
          07.01.2017 12:55

          В данном случае, нам нужно чтобы для одного пароля был один и тот же ключ — всегда. Поэтому рандомная соль не подходит, а преимущество псевдорандомной соли(основанной на пароле) перед константной сомнительна


          1. agee
            07.01.2017 13:19

            Вам ничего не мешает сгенернную соль прикрепить к шифротексту так, как Вы поступаете с nonce и MAC. Вы говорите, преимущества рэндомной соли сомнительно, а в документе, который я привел, говорят обратное. Более того, соль как минимум должна быть уникальной, но уж точно не константной. В этом и вообще ее смысл ведь!

            Почему ключ должен быть один и тот же для одного пароля? По-моему главное, чтобы коюч подходил к конкретному шифротексту, а не ко всем! Ведь если (теоретически, конечно ;), скомпрометируется один ключ, остальные шифротексты останутся целыми


            1. kwolfy
              07.01.2017 13:39

              В будущем планируется добавить функцию шаринга файлов по ссылке и для каждого файла и так будет свой собственный ключ.

              В контексте когда вы не знаете об этой функции — вы правы, а вот я знаю.

              Пока писал коммент понял, что не прав.
              Основная функция соли — усложнить создание радужных таблиц путем уникализации хеш-функции для каждого пользователя. Вся проблема была в том, что у приложения нет базы данных, а я не рассматривал компроментацию аккаунтов dropbox пачкой, хотя следовало


        1. kwolfy
          07.01.2017 12:59

          Что касается замены на scrypt — это для усложнения перебора


        1. kwolfy
          07.01.2017 13:08

          Если уже сильно придираться, один из рассматриваемых вариантов — при первой авторизации генерировать рандомную соль, шифровать его ключем на основе константной соли и записывать как файл в dropbox, а при следующей авторизации — получать этот файл, расшифровать и на основе этой соли уже получить ключ. Но и это на мой взгляд не особо эффективно.
          Есть есть какие то предложения по этому поводу, рад буду услышать


  1. ArjLover
    05.01.2017 23:33
    +1

    А что делать с клиентом на мобилке в таком случае?


  1. lexore
    06.01.2017 15:43

    Под катом будет описан один из способов скрыть свои файлы так, чтобы ваш параноик был счастлив.

    Открываю сайт...


    Для того чтобы воспользоваться сервисом, необходимо авторизоваться с помощью Dropbox OAuth.
    CryptDropibox хочет получить доступ к своей папке Приложения › EnryptedFiles в вашем Dropbox.

    Хм, хм…
    А что делать, если мой параноик не хочет давать стороннему сайту dropcryptbox.com доступ к своей папке в Dropbox?


    1. kwolfy
      06.01.2017 18:35

      Скоро будет открыт код и каждый сможет у себя развернуть свою локальную версию


  1. serf
    06.01.2017 20:26

    Duplicati делает шифрования перед заливкой куда-либо.