end-to-end шифрование файлов в dropbox
У каждого есть свои тайны и человечество вечно пыталось находить пути как их скрытия так и разоблачения.
Под катом будет описан один из способов скрыть свои файлы так, чтобы ваш параноик был счастлив
Не могу сказать, что я параноик до мозга костей, но бывают случаи когда мне нужно быть уверенным, что информация не попадет куда не надо, но при этом и не потеряется.
Хочу заметить, что я не претендую на звание «уникальный проект», есть 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
Демо https://dropcryptbox.com
Совсем скоро код будет размещен на github
Комментарии (3)
5 января 2017 в 15:10
+1↑
↓
Интересный вариант. Лично я поступил по-другому. Создал encfs-раздел на локальной системе. В Dropbox положил зашифрованный каталог. В итоге получается что в сторадже есть и обычные нешифрованные файлы и папка с «кракозябрами»
5 января 2017 в 15:15
0↑
↓
А почему решили делать эксклюзивно для дропбокс?Не легче ли просто зашифрованные файлы ложить в папку синхронизации на пк, которые потом уже в шифрованном виде отгружаются на дропбокс?
Таким образом можно было бы использовать для всех облачных хранилищ одновременно
5 января 2017 в 15:22
0↑
↓
Была цель реализовать проект насколько возможно быстро — поэтому dropboxВаш вариант тоже интересен, но у меня есть много идей которые требуют взаимодействия с именно файловым сервером, а не локальной папкой