Использование WebCrypto для генерации ключа ECDH из PBKDF2

1

ПРЕДУПРЕЖДЕНИЕ Следующее не предназначено для одобрения конвертирования паролей в ключи ECDH. Создайте ключи ECDH из высокоэнтропийных криптозащищенных PRNG.

Я хочу взять в секрете и создать из него открытый/закрытый ключ ECDH.

В браузере обычным способом было бы использовать PBKDF2 (или другие детерминированные байты) для создания пары открытых/закрытых ключей ECDH в WebCrypto.

Следующий пример кода должен сделать это, но он выбрасывает исключение DOM в Chrome:

// Generate a random KDF key.
const priv = new Uint8Array(24)
crypto.getRandomValues(priv)
const kdfKey = await crypto.subtle.importKey(
  'raw', priv, { name: 'PBKDF2' }, false, ['deriveKey'])

// Derive the ECDH key.
const salt = new Uint8Array(16)
const iterations = 2000
const hash = { name: 'SHA-512' }
const curve = { name: 'ECDH', namedCurve: 'P-384' }
const usages = ['deriveKey']

crypto.getRandomValues(salt)

const ecdhKey = await crypto.subtle.deriveKey({
  name: 'PBKDF2', salt, iterations, hash
}, kdfKey, curve, true, usages) // throws.

Вышеупомянутое работает, когда алгоритм AES-GCM (т. AES-GCM Когда кривая заменяется, например, { name: 'AES-GCM', length: 256 }), но другие алгоритмы также вызывают исключения, поэтому я подозреваю, что что-то не хватает... тонкий.

Моя надежда заключалась в том, что WebCrypto подходит для приема случайных битов и создания пары открытых/закрытых ключей ECDH. Похоже, это не так.

Альтернативой было бы использование PBKDF2 для получения deriveBits которые можно использовать для ручного создания пары ключей ECDH. Если это действительно единственный вариант, каков обычный алгоритм для превращения случайных битов в открытый/закрытый ключ (т.е. ссылки и публичные реализации)? Если мне нужно что-то развить, я, скорее всего, опубликую здесь интерес и обзор.

EDIT: Дополнительная информация о прецеденте

Использование PBKDF является попыткой избежать необходимости генерировать открытый ключ (x и y) пары ключей ECDH при задании параметра (private) d. x и y являются производными и поэтому их не нужно хранить, и у нас очень ограниченный хранилище данных - подходит только для частного ключа, например 192 бит, более или менее (PBKDF также может сгладить размер бита, но что в стороне).

Если WebCrypto вычислил x и y при заданном (псевдо) случайном d параметре, желаемый результат мог быть достигнут/проиллюстрирован следующим образом:

>>> curve = { name: 'ECDH', namedCurve: 'P-256' }
>>> k = await crypto.subtle.generateKey(curve, true, ['deriveKey'])
>>> pri = await crypto.subtle.exportKey('jwk', k.privateKey)
>>> delete pri.x
>>> delete pri.y
>>> k2 = await crypto.subtle.importKey('jwk', pri)
    ^^ errors

PBKDF используется для генерации (AES) ключей в многочисленных примерах. Я надеялся, что функциональность вычисления x и y для эллиптических кривых, уже существующих в WebCrypto, будет доступна через PBKDF2 deriveKey.

Альтернатива "сам по себе" в Javascript заключается в анализе JWK/Base64 (вариант URL), затем используйте функцию с большим числом с модульной арифметикой (например, теорему Ферма Литл) и, наконец, записывайте функции для добавления, удвоения эллиптической кривой, умножение. Это то, что я сделал (математика ECC здесь). Но я надеялся, что все это будет лишним, поскольку код для этого точно существует в WebCrypto, и я просто надеялся использовать либо importKey либо deriveKey чтобы использовать его.

Просто повторю: нет паролей, созданных пользователем; использование такого типа для генерации ключа ECDH считается неразумным.

Теги:
cryptography
diffie-hellman

3 ответа

2

Брайан,

Невозможно детерминистически создать пару ключей из пароля с использованием WebCrypto.

Сожалею.

Вы можете детерминистически создать пару ключей из пароля в Javascript, а затем импортировать эту пару ключей, если она является ключом secp256r1 в правильном представлении.

Существует несколько библиотек javascript, которые поддерживают детерминистическое создание пары ключей из пароля. Я не могу делать какие-либо утверждения о правильности или безопасности этих библиотек или если есть те, которые делают это для secp256r1. Конечно, генерация ключей - один из самых важных аспектов, который следует учитывать при использовании криптографии, и это делается на основе слабого источника энтропии.

Если вы решите продолжить этот подход, несмотря на то, что этот импорт ключа определенного типа довольно прост, см. Https://github.com/diafygi/webcrypto-examples#ecdsa---importkey

TL; DR ваши мили будут отличаться при таком подходе, но это возможно.

Райан

  • 0
    Большое спасибо Райан. Я так и подозревал, и ваше предложение было моим запасным планом. Есть ли у вас какие-либо ссылки на стандарты, которые бы указывали, почему PBKDF2 можно использовать для создания AES, а не ключей ECDH?
  • 0
    Как правило, вы не найдете стандартов, говорящих о том, почему что-то обычно не является хорошей идеей. Тем не менее, в случае генерации ключа вам нужен ключ, который трудно угадать, случайность учитывается даже в ECDH. PBDKF2 - это попытка высечь шелковую сумку из уха свиноматки. Энтропия, которую вы получаете из пароля, плохая, 50 000 итераций PBDKF2 лучше, чем ничего, но она не дает вам хороший секретный ключ, если ввод не был уже хорошим секретным ключом.
Показать ещё 3 комментария
2

"Тонкий". Неплохо!

SubtleCrypto.generateKey()

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

(async function() {
    const algo = {
        "name": "RSASSA-PKCS1-v1_5",
        "modulusLength": 256,
        "publicExponent": new Uint8Array([0x01, 0x00, 0x01]),
        "hash": {
            "name": "SHA-256"
        }
    };
    const extractable = true;
    const keyUsages = ["sign","verify"];
    const result = await crypto.subtle.generateKey(algo, extractable, keyUsages);
    console.log(result);
})();
  • 0
    Спасибо за пост. Итак, учитывая секрет ( Uint8Array или string ), как использовать данную функцию для (пере) генерации ECDH ключей ECDH ? Генерация случайного ключа ECDH проста, то есть subtle.generateKey(curve, false, ['deriveKey']) где curve , например, {name: 'ECDH','namedCurve: 'P-384'} , но неясно, как импортировать , получить или детерминистически сгенерировать пару ключей.
0

Из обновления мы все еще не можем сказать, что такое вариант использования, мы можем сказать (я думаю), что ваша цель - сэкономить место для хранения по какой-то причине. Ключи ECC довольно малы, трудно представить, какой вариант использования будет особенно в веб-приложении, где такой небольшой объем хранилища потребует использования более слабого подхода. Тем не менее, более ранний ответ остается тем же, невозможно сделать то, что вы хотите, с помощью webcrypto напрямую.

  • 0
    Не могли бы вы объяснить, что вы подразумеваете под "более слабым подходом"? Так как PBKDF2 не уменьшает энтропию для секретных эквивалентов с битовой длиной, я предполагаю, что вы имеете в виду некоторую другую слабость, и если это так, я был бы благодарен за разъяснения. Я ожидаю, что наиболее существенным недостатком DIY keygen является, вероятно, DoS и процесс восстановления из-за неправильной реализации (отсюда и желание WebCrypto). В любом случае, ваша точка зрения на неспособность WebCrypto отмечена, и я отмечу ваш другой ответ наградой.
  • 0
    Между прочим, цель сериализации « d only» - для ключей восстановления в автономном режиме / «sneaker net», которые должны быть записаны / переданы людьми и объединены с простым кодом с исправлением ошибок. Не думая о простом способе объяснить это в то время, размер хранилища - это метафора, которая впервые пришла в голову как аналог, который поможет объяснить это.
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню