Заранее извиняюсь за входящий Wall-O-Text . Это (по крайней мере, для меня) довольно сложная проблема, над которой я довольно много думал. Вы можете прочитать мой вопрос, а также увидеть тестовую реализацию в Ruby (очень спешно построенную, не поддерживаемую базой данных, и, вероятно, очень уродливую) на этой GitHub Gist , если вы так склонны.
Введение
Представьте себе, что для создания веб-системы управления паролями нужно было
(через SSL! :) со следующими требованиями:
- Отдельные пользователи входят в систему, используя свой уникальный проход
фраза.
- Этой парольной фразы должно быть достаточно, чтобы позволить пользователю использовать систему
эффективно (например, со смартфона и т. д.) - суть в том, что они
не должен иметь при себе файл ключа.
- Пользователи могут хранить в системе биты произвольной длины («записи»).
- Записи зашифрованы в базе данных таким образом, что нет
достаточно информации только в базе данных или приложении, чтобы прочитать
зашифрованные записи.
- Пользователи должны иметь возможность «делиться» записями с другими пользователями системы.
чтобы другие пользователи могли читать содержимое записи.
Я не специалист по криптографии. Подумав некоторое время, я подошел
со следующим. Мой вопрос : безопасна ли эта реализация? Я
что-то упустил? Если да, то является ли приведенная выше спецификация вообще осуществимой? Или это
излишество?
База данных
База данных настроена так:
+------------------------------------------------------------------------------+
| users |
+---------+--------------+--------------+---------------+----------------------+
| salt | pub_key | enc_priv_key | priv_key_hmac | |
+---------+--------------+--------------+---------------+----------------------+
| entries |
+---------+--------------+--------------+---------------+----------+-----------+
| user_id | parent_entry | enc_sym_key | sym_key_sig | enc_data | data_hmac |
+---------+--------------+--------------+---------------+----------+-----------+
Основные случаи использования
Давайте представим двух пользователей системы, Алису и Боба.
Bob регистрируется на сайте :
- Боб вводит пароль. Этот пароль отправляется на сервер (но не
сохранены).
- Сервер генерирует случайную соль и сохраняет ее в поле
salt
.
- Сервер генерирует хэш SHA-256 для пароля и соли Боба.
- Сервер генерирует пару ключей RSA. Открытый ключ хранится как обычный
текст в поле
pub_key
. Закрытый ключ шифруется через AES-256
используя хеш, сгенерированный из пароля Боба и соли в качестве ключа и
хранится в поле enc_priv_key
.
- Сервер генерирует код аутентификации сообщений на основе хэша для Боба
закрытый ключ, используя пароль Боба и соль в качестве ключа, и сохраняет его в
поле
priv_key_hmac
.
Боб сохраняет запись в системе :
- Боб вводит некоторые данные для хранения вместе со своим паролем.
Эти данные отправляются на сервер.
- Сервер генерирует ключ, который будет использоваться в качестве ключа для шифрования AES-256.
- Сервер использует этот ключ для шифрования данных и сохраняет результат в
поле
enc_data
.
- Сервер генерирует код аутентификации сообщений на основе хеш-функции для
данные с использованием сгенерированного ключа и сохраняет его в поле
data_hmac
.
- Симметричный ключ, используемый для шифрования данных, зашифрован с помощью открытого Боба
ключ и сохраняется в поле
enc_sym_key
.
- Сервер использует личный ключ Боба для генерации подписи
симметричный ключ.
Боб получает свою сохраненную запись :
- Боб вводит свой пароль и идентификатор записи для извлечения.
- Сервер генерирует хэш SHA-256 для пароля и соли Боба.
- Зашифрованный закрытый ключ Боба расшифровывается с помощью шифрования AES-256 с использованием
хэш.
- Сервер проверяет, что зашифрованный закрытый ключ Боба не был
вмешиваться, проверяя HMAC в
priv_key_hmac
.
- Сервер расшифровывает симметричный ключ, хранящийся в поле
enc_sym_key
используя личный ключ Боба.
- Сервер проверяет, что зашифрованный симметричный ключ не был взломан
с проверкой подписи в
sym_key_sign
с использованием открытого ключа Боба.
- Сервер расшифровывает данные с помощью симметричного ключа.
- Сервер проверяет, что зашифрованные данные не были подделаны, проверяя HMAC, сохраненный в поле
data_hmac
. - Сервер возвращает расшифрованные данные Бобу.
Боб делится записью с Алисой :
- Боб хочет, чтобы Алиса имела доступ к записи, которой он владеет.Он вводит свой пароль и идентификатор записи для совместного использования.
- Данные для записи расшифровываются с использованием метода из «Боб получает свою сохраненную запись».
- ДляАлиса так же, как в «Боб хранит запись в системе», со следующими исключениями:
- Запись
parent_entry
установлена на запись Боба. - Подпись для симметричногоключ рассчитывается с использованием личного ключа Боба (поскольку личный ключ Алисы недоступен Бобу).
- Когда Алиса получает доступ к этой новой записи, существование ненулевого
parent_entry
заставляет систему использовать открытый ключ Боба.проверить подпись (поскольку его закрытый ключ использовался для ее создания).
Боб изменяет данные в своей общей записи :
- Боб решает изменить данные в записи, которой он поделился с Алисой.Боб указывает идентификатор записи для изменения и новые данные, которые он должен содержать.
- Система перезаписывает данные, созданные в «Боб сохраняет запись в системе».
- Система находит каждую запись с помощью
parent_entry
равно записи, которая была только что изменена, и для каждой перезаписывает данные, созданные в «Боб разделяет запись с Алисой».
Анализ
Преимущества:
- Невозможно расшифровать какие-либо данные из базы данных без пароля пользователя, которому принадлежат данные, поскольку закрытый ключ, необходимый для расшифровки данных, зашифрован паролем пользователя, и этот пароль (иэто хэш) не хранится в базе данных.
- Если пользователь хочет изменить свой пароль, необходимо восстановить только его зашифрованный закрытый ключ (расшифровать закрытый ключ с помощью старого пароля / хэша, затем повторно зашифроватьс новым паролем / хэшем).
- Общие записи хранятся в базе данных как отдельные записи, поэтому нет необходимости передаватьключ между несколькими пользователями / группами пользователей.
Недостатки / проблемы (о которых я могу думать):
- Если общая запись изменена, система должна повторношифровать каждую дочернюю запись;при большом количестве пользователей, разделяющих данные, это потенциально может быть вычислительно дорогим.
- Общие записи зависят от открытого ключа родительского пользователя для проверки подписи.Если пользователь удален или его ключ изменен, подписи недействительны.
Повторяется после введения: мой вопрос: безопасна ли эта реализация?Я что-то пропустил?Если да, то является ли приведенная выше спецификация вообще осуществимой?Или это перебор?
Спасибо за то, что выложили это так долго.Мне интересно ваше мнение!Я на правильном пути или полный идиот?ВАМ РЕШАТЬ!:)