Вступление
Схема разделение секрета, ключа или пароля не новая, но во всех спецификациях, которые я встречал есть главный недостаток — доли и сам секрет различимы по структуре или длине. To есть по каждой доле разделяемого секрета можно было сказать это "доля", а не настоящий секрет.
Хотелось бы посмотреть в другую сторону и сделать совершенную схему, в которой
- восстановить секрет можно только имея из долей
- длина доли и секрета была одной и той же
- у доли не было бы структуры, то есть доля была похожа на случайную последовательность байт
- каждая доля сама по себе были бесполезные. Более того, количество долей меньших тоже были бесполезными и не раскрывали искомого секрета
- длина искомого секрета могла быть любой
- при утере долей, меньших , можно было разделить секрет на доли заново, а после этого уничтожить оставшиеся доли. Тем самым секрет никогда не будет восстановлен по утерянным долям.
Исследование
В статье на википедии представлены несколько способов по разделению секрета, для моих целей самая практичная и простая из них — пороговая схема Шамира.
Идея крайне проста —
- Задается произвольный многочлен коэффициентами , где является секретом.
- Вычисляются N точек , которые и представляют собой доли ( ).
Доли — (1,-2), (2,-1), (3,2), (4,7). Любых 3х долей достаточно, чтобы получить f(0)
Итого, из любых точек можно составить линейных уравнений, подставляя и в общий вид многочлена. линейных уравнений дают однозначное определение коэффициентов, где является исходным секретом. Причем из числа точек меньшего , может принимать абсолютно любое значение при степени многочлена .
Но работать с рациональными числами и целыми числами мы не можем, по причине того, что зная алгоритм генерирования коэффициентов, можно сузить число возможных варианта секрета, подробнее об этой проблеме тут.
Поэтому мы переходим к вычетам по модулю простого числа . В этом поле элементов от до . Естественно, выбираем , чтобы наш секрет принадлежал этому полю.
Преимущества
- Длины секрета и долей примерно равны, если выбираем близкое к
- Длины секретов могут быть любыми
- Можно сколько угодно раз разделить секрет заново, так как "много" многочленов степени
- По долям, меньших , невозможно восстановить секрет, либо часть его
Проблемы
- Для больших длин секретов приходилось бы искать большое простое число, заведомо большее длины секрета, чтобы секрет находился в этом поле.
Для секрета длиной 8 байт простое число должно быть не меньше 1,8e19.
Нахождения простого числа, большего заданного задача нетривиальная. Да и работа с большими числами на практике сложная. - Доля в схеме Шамира это точка с координатам и . Длина секрета и координаты доли равны, но где-то нужно хранить координату . Так как мы хотим получить идеальную схему разделения, чтобы длины секрета и ключа совпадали, мы не можем добавить её к нашей доле конкатенацией.
Схема Шамира была самой подходящей для решения мой задачи, поэтому алгоритм chipndale будет основан на ней.
Chipndale
Chipndale разделяет секрет по байтам, то есть секрет должен иметь длину, кратную байту. Так же секрет не может иметь длину меньше 8 байт, так как меньшее число байт является ненадежным секретом само по себе.
В алгоритме задается — максимальное количество долей, на которое делится секрет — в моей реализации это 5, но на самом деле их может быть и больше.
Ограничение
- Секрет — последовательность байт длины
- Длина секрета ? 8 байт
- Максимально возможное (которое в конкретной реализации можно расширить)
Решение описанных проблем
Решение проблемы №1
Для того, чтобы не работать с большими числами мы сперва разобьем наш секрет на байты, тогда минимальное простое число будет , и каждый байт по отдельности разделим по схеме Шамира.
То есть из 256 значений секрета мы получаем 257 значений доли, но тогда доля будет иметь больший размер, чем искомый секрет, что нам не подходит.
Для того, чтобы размерность секрета и доли совпадала мы перейдем от поля вычетов простого числа к полю Галуа в котором число элементов равно .
Если поле вычетов по модулю простого числа задается простым числом , то поле
Галуа задается числами , и неприводимым многочленом степени .
Так как деление побайтовое = 256 при p=2, n=8.
С неприводимым многочленом сложнее, их несколько для одних и тех же значений и . Я выбрал тот, которых используется в AES (п 4.2) — 0x11b.
Таким образом, проблема решена: больше не нужно работать с большими простыми числами и множество значений доли совпадает с множеством значений секрета.
Решение проблемы №2
Для решение второй проблемы в значении функции сделаем проверочный вектор, который позволит расположить доли в единственном порядке.
Сам код проверки будет иметь длину 4 байта и вычисляться на основании исходного секрета и случайного ключа длины .
Рассчитываться будет по следующей формуле
Индексы показывают длину величины в байтах. От результата функции берутся первые 4 байта.
Случайное число нужно для того, чтобы злоумышленник имея долей не мог определить секрет, перебирая всевозможные значения секрета.
Разбиение секрета
- Генерируем координаты длины , точек , где
- Секрет будет иметь координаты
- Генерируем ключ длиной байта
- Вычисляем контрольную сумму , тем самым получаем точку с координатами
- Вычисляем оставшиеся точек c координатами на основании точек из 1,2,3 пунктов по формуле Лагранжа.
- Проверяем, что любая перестановка по координатам сочетаний , кроме одной, дает неверную контрольную сумму. Это и есть условие однозначного декодирования.
Наглядно картина разделения chipndale выглядит так:
Подробное описание есть в спецификации
Восстановление секрета
Переставляем из долей по координатам , вычисляя и по формуле Лагранжа, пока не совпадет контрольная сумма.
Если контрольная сумма совпала, значит вектор и является искомым секретом.
Если нет таких координат, значит доли неверные или недостаточные.
Восстановить секрет имея число долей, меньших К-1
Если имеется долей, то восстановить секрет невозможно.
Если мы имеем долей, то для восстановления секрета нам потребуется сгенерировать ключей и для каждого подобрать оставшуюся часть секрета — , чтобы совпадал код-аутентификации.
Итого имеем, что для атаки грубой силой нужно перебрать значений и тогда получим возможных значения секрета.
То есть сокращение возможных вариантов секрета в 4,2e9 раз.
На самом деле это небольшая цифра, как могло показаться.
Кол-во байт секрета | Кол-во значений секрета | Кол-во значений секрета, имея K-1 долей |
---|---|---|
8 | 256**8 = 1,8e19 | 256**4 = 4,3e9 |
16 | 256**16 = 3,4e38 | 256**12 =7,9e28 |
32 | 256**32 = 1,1e77 | 256**28 = 2,7e67 |
В сравнительной таблице видно, что множество вариантов значений секрета хоть и сужается, но не дает практической пользы, так как кол-во вариантов секретов все равно слишком большое.
Поэтому для упрощения можно считать, что отдельные долей являются бесполезными.
Генератор случайных чисел
Для разделения секрета по схеме Шамира или chipndale требуются случайные числа для долей секрета. Если злоумышленник знает алгоритм генерации случайных чисел, то он знает , а также доли. Это может быть вектором атаки.
Например, если злоумышленник так же владеет одной К-1 долей тоже, он может перебрать значений и подобрать секрет.
Всегда используйте только надежные источники случайных чисел.
Действия в случае утере доли(ей)
При потере долей таким образом, что осталось менее частей, можно считать, что секрет утерян полностью без возможности восстановления.
В ином случае у Вас осталось частей, и нужно
- Восстановить секрет из любых оставшихся долей.
При утере долей большем либо равным нужно пересоздать сам секрет и заменить его во всех местах использования.
При утере менее долей пересоздавать секрет не нужно. - Разделить секрет на доли заново.
- Предыдущие оставшиеся доли обязательно уничтожить
При утере долей существует малая вероятность, что, если
- к злоумышленнику попали долей
- злоумышленник знает, что это доли одного секрета
- злоумышленник знает, что делать с восстановленным секретом
- злоумышленник воспользовался секретом до того, как Вы пересоздали секрет
то секретные данные утекли. Во избежание такой ситуации проверяйте сохранность долей и при потери хотя бы одной доли, пересоздавайте доли заново, уничтожая оставшиеся предыдущие доли, тогда искомый секрет будет в безопасности.
Заключение
Тем самым мы получили схему деление секрета Chipndale-K-N, в которой
- секрет и доли неразличимы по структуре, что позволяет правдоподобно отрицать существование реального секрета
- только из участников могут получить первоначальный секрет
- искомый секрет может иметь любую длину
- секрет может быть поделен на части сколь угодно много раз в случае утери как-либо из частей.
К недостаткам алгоритма можно отнести, что максимальное теоретически возможное число долей 254. Сложность алгоритма растет пропорционально факториалу максимальному числу долей, т.е. , поэтому теоретическое число долей вряд ли возможно.
В мой реализации максимальное число долей равно 5.
Демо
Я создал страницу с реализацией chipndale
https://ilyadt.github.io/chipndale/
Код полностью открытый и доступен в репозитории https://github.com/ilyadt/chipndale/
Сама библиотека покрыта юнит-тестами, а так же есть тестовые вектора для проверки разделения секрета. Например:
{
"n": 4,
"k": 2,
"secret": "b1008f3a39a4466147f26f925bcabbecebc7549a8c2005ce1e176f7e224f2b74",
"randomCsKey": "1f5e6947af4d06540936e9acdf13ed0c77bae41a54ca92e698271cf3",
"randomCoordinateVector": [],
"shares": [
"3632a9812836077bae41a54ca92e6982227ca01874960883d4617c70d3323f05",
"a464c3571b9bc4558e8fe035a419043062aaa78567571f5491fb4962dbb50396",
"2356e5ec0a09854f673c2aeb56fdd65eab1153079fe112195b8d5a6c2ac817e7",
"9bc817e07dda5909ce086ac7be77de4fe21da9a441ce31e11bd42346cba07bab"
]
}
Федерация
Схема разделения chipndale может быть применена как федерация, то есть любая доля может быть поделена на доли.
Например, я хочу, чтобы секретом мог воспользоваться только я, но в случае утери, я бы мог попросить семью или друзей восстановить секрет.
Тогда я делю искомый секрет по схеме SH1,SH2,SH3=Chipndale-2-3(s). SH1, SH2 оставляю себе и храню в разных местах, тем самым я могу воспользоваться секретом самостоятельно. SH3 делю следующим образом — SH3a1, SH3a2, SH3a3, SH3a4 = Chipndale-2-4(SH3) и раздаю доли 4 друзьям, и в случае потери доли мною любые 2 друга вместе со мной восстановят секрет. А также делю SH3b1, SH3b2, SH3b3, SH3b4 = Chipndale-5-3(SH3) и раздаю семье, тем самым в случае утере доли мною, я могу попросить 3 членов семьи восстановить секрет. Причем семья и друзья без меня восстановить секрет не смогут.
aleks_raiden
Интересно, надо изучать. А можно ли ваш подход использовать для очень больших разделений? Например, где миллион(ы) долей и сотни тысяч минимальный порог?
ilya_dt Автор
Нет, так как я использую поле Галуа из 256 элементов, максимальное теоретическое число долей 256 — 2 = 254.
А практически для деления и восстановления секрета нужно maxShares! операций, что очень трудоемко, поэтому я ограничил maxShares 5.