Учебник по использованию собственных функций шифрования-дешифрования MetaMask

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

В этом руководстве я использую нотацию TypeScript, потому что считаю, что это помогает понять, что происходит. Пожалуйста, удалите типы из кода, если вы используете JavaScript.

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

Криптография с открытым ключом

Вот лишь краткий обзор криптографии с открытым ключом. Основная идея заключается в том, что у вас есть открытый и закрытый ключи, связанные некоторыми математическими свойствами. Если вы шифруете сообщение с помощью открытого ключа, только закрытый ключ может его расшифровать. Это означает, что вы можете поделиться открытым ключом с другими людьми. Затем они могут использовать его для шифрования сообщений, которые можете расшифровать только вы. Более того, шифрование работает наоборот, обычно используется для подписи сообщений.

Существенным для нас является то, что если Алиса хочет отправить секретное сообщение Бобу, для этого потребуются следующие шаги:

  1. Боб отправляет Алисе свой открытый ключ
  2. Алиса шифрует сообщение, используя открытый ключ Боба.
  3. Алиса отправляет зашифрованное сообщение Бобу
  4. Боб расшифровывает сообщение, используя свой закрытый ключ

Криптография является важной частью Интернета, независимо от количества, и, на мой взгляд, каждый разработчик должен знать хотя бы основы криптографии. Для получения дополнительной практической информации я рекомендую следующую книгу:



Шифрование метамаски

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

Большая часть информации об этой функции содержится в документации MetaMask:



Я упомяну об этом позже, но в документации пропущен тот факт, что расшифровка работает только в том случае, если обычный текст содержит допустимую кодировку UTF-8. Это не будет работать для произвольных последовательностей байтов!

1. Боб отправляет Алисе свой открытый ключ

Первый шаг — получить открытый ключ Боба и отправить его Алисе. Этот ключ необходим для шифрования, и им можно поделиться. Фактически, вы делитесь этим ключом с каждой отправляемой транзакцией блокчейна. Возможно, вы уже знаете, что адрес учетной записи не совпадает с открытым ключом. Адрес вычисляется как хэш открытого ключа, что делает невозможным простой расчет открытого ключа исключительно на основе адреса пользователя (неудачное решение, на мой взгляд).

Сначала нам нужно запросить открытый ключ у MetaMask. Мы можем использовать функцию eth_getEncryptionPublicKey, предоставленную MetaMask. Использование этой функции относительно просто; просто передайте адрес аккаунта. Приложение должно иметь доступ к указанной учетной записи; пройти случайный аккаунт не получится.

Примечание: MetaMask автоматически внедряет объект window.ethereum на веб-сайты. Если вы используете какую-либо библиотеку для связи с MataMask, вам может потребоваться другой доступ к этому объекту (часть запроса будет такой же).

Теперь, когда у вас есть открытый ключ, вы можете отправить его Алисе, чтобы она могла использовать его для шифрования. Хорошая новость заключается в том, что открытый ключ помещается в переменную bytes32; следовательно, вы можете легко передать его смарт-контрактам. Или вы можете использовать любой другой способ обмена открытым ключом.

2. Алиса шифрует сообщение с помощью открытого ключа Боба.

Получив открытый ключ, мы можем приступить к шифрованию сообщения. Вам нужно будет установить пакет из MetaMask:@metamask/eth-sig-util , обеспечивающий функцию шифрования. Затем для шифрования данных, предоставленных как Buffer, мы используем следующую функцию (открытый ключ такой же, как полученный на предыдущем шаге):

Важно:MetaMask расшифровывает только допустимые последовательности UTF-8, поэтому, если вы хотите отправлять произвольные байты, вы должны сначала закодировать их, используя что-то вроде base64. Я использую base85, предоставленный пакетом ascii85. Я пытался сэкономить как можно больше места, так как мы храним зашифрованные данные в смарт-контракте.

3. Алиса отправляет зашифрованное сообщение Бобу.

Обмен зашифрованными сообщениями зависит от вас. Мы используем смарт-контракт для хранения и обмена зашифрованными сообщениями. В вашем смарт-контракте вы, вероятно, будете использовать тип bytes для хранения зашифрованного сообщения. Мы также используем пакет ethers.js для взаимодействия со смарт-контрактом, который требует тип number[] при отправке данных в аргумент bytes. Если вы хотите сделать то же самое, вы можете преобразовать буфер в тип number[] следующим образом:

numberArray = buffer.toJSON().data;

4. Боб расшифровывает сообщение, используя свой закрытый ключ.

Наконец, когда Боб получает зашифрованные данные, он может восстановить исходный объект и запросить у MetaMask его расшифровку. Все это делается с помощью следующей функции (data buffer — это буфер, выдаваемый функцией шифрования):

С точки зрения пользовательского опыта, функция расшифровки MetaMask довольно удобна. Он полностью скрывает закрытый ключ от приложения. Более того, пользователю не нужно обрабатывать закрытый ключ вручную. Единственным недостатком является всплывающее окно, которое всегда запрашивает разрешение пользователя на расшифровку.

Бонус: реализация на Python

Теперь мы оказались в ситуации, когда нам нужно было взаимодействовать со смарт-контрактом также с помощью Python. В таком случае нам нужны соответствующие функции шифрования/дешифрования, реализованные в Python. Вам нужно будет установить PyNaCl, который предоставляет функции шифрования и дешифрования. Затем вы можете использовать следующий код:

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

Заключение

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

В любом случае, если вам понравилась статья, рассмотрите возможность подписаться на меня и @FELT_Labs. Будут еще статьи о разработке Web3.