Как защитить сообщения в EOS

in #eos2 years ago (edited)

Оригинал: https://medium.com/coinmonks/how-to-secure-messages-on-eos-ebb869a459ea

Блокчейн - это распределенная книга, и каждый блок данных общедоступен для всеобщего обозрения. Возможно, вам интересно, что делать, если вы хотите зашифровать сообщения на блокчейне, в частности, на EOS?

Как обеспечивается безопасность сообщений на Блокчейне

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

Вот как это работает:

  1. У Алисы есть конфиденциальные данные, на которые она хочет иметь возможность делегировать доступ.
  2. Алиса шифрует свои данные с помощью собственного публичного ключа и сохраняет его в облаке или децентрализованном хранилище.
  3. Алиса делегирует доступ к Бобу. Данные переустановлены на ключ Боба в хранилище.
  4. Боб загружает данные и расшифровывает их своим приватным ключом.

Защита сообщения в EOS

Мы начнем со сценария, в котором у Алисы и Боба есть доступ к приватному ключу, и Алиса хочет отправить важные данные Бобу, а также использовать pyUmbral, который является наилучшей реализацией NuCypher’s для Umbral (split-key threshold - proxy re-encryption).

Давайте сначала создадим очередь сообщений смарт-контрактов на EOS.

Создадим одну таблицу, называемую сообщениями, которая содержит uint64_t msg_id, account_name from, account_name to, строковый зашифрованный текст, и строчную капсулу. msg_id - первичный ключ.

Здесь предусматриваются два действия: sendmsg и deletemsg. sendmsg требует account_name from и to, msg_id, шифртекст и капсулу. Шифрованный текст - это зашифрованное сообщение, а капсула - это концепция в Umbral, которая генерируется с использованием pyUmbral. Deletemsg в основном принимает msg_id, проверяет to имя учетной записи, а затем удаляет запись.

   public:
       using contract::contract;
       //@abi action
       void sendmsg( account_name from, account_name to, uint64_t msg_id, const std::string & ciphertext, const std::string & capsule) {
           require_auth( from );
           messages_index messages( _self, _self );
           auto itr = messages.find(msg_id);
           if (itr != messages.end()) {
               std::string error = "msg_id already exists: " + std::to_string(msg_id);
               eosio_assert(false, error.c_str());
           }
           messages.emplace( from, [&](auto& msg){
               msg.msg_id = msg_id;
               msg.from = from;
               msg.to = to;
               msg.ciphertext = ciphertext;
               msg.capsule = capsule;
           });
       }
       // @abi action
       void deletemsg( account_name to, uint64_t msg_id) {
           require_auth( to );
           messages_index messages(_self, _self);
           auto itr = messages.find(msg_id);
           if ( itr == messages.end() ) {
               std::string error = "msg_id does not exist: " + std::to_string(msg_id);
               eosio_assert(false, error.c_str());
           }
          
           if ( itr->to != to ) {
               std::string error = "Receipient not correct: " + eosio::name{itr->to}.to_string();
               eosio_assert( false, error.c_str());
           }
        
           messages.erase(itr);
        }
   private:
       //@abi table messages i64
       struct messages {
           uint64_t msg_id;
           account_name from;
           account_name to;
           std::string ciphertext;
           std::string capsule;
           uint64_t primary_key() const { return msg_id;}
       };
      
       typedef eosio::multi_index<N(messages), messages> messages_index;
};
EOSIO_ABI( queue, (sendmsg)(deletemsg) )



Скомпилируйте его:

eosiocpp -g queue.abi queue.cpp


Создайте учетную запись, чтобы загрузить смарт-контракт:

executed transaction: a767af2c66857...  200 bytes  3309 us
# eosio <= eosio::newaccount            {"creator":"eosio","name":"queue","owner":{"threshold":1,"keys":[{"key":"EOS5aEqZf22dfThTR8GGMnD8oFv...
$ cleos set contract queue ../queue
Reading WAST/WASM from ../queue/queue.wasm...
Using already assembled WASM...
Publishing contract...
executed transaction: 38e94741c...  13824 bytes  9561 us
# eosio <= eosio::setcode               {"account":"queue","vmtype":0,"vmversion":0,"code":"00617ee7e...
# eosio <= eosio::setabi                {"account":"queue","abi":"0e656f73696f3a3a6162692f9640675...


Создайте тестовые учетные записи Алисе и Бобу:

executed transaction: f0c42065f6d9fc...  200 bytes  243 us
# eosio <= eosio::newaccount            {"creator":"eosio","name":"alice","owner":{"threshold":1,"keys":[{"key":"EOS6NU3XEvosgRVEbhrBHrkbYVt...
$ cleos create account eosio bob EOS7cX17CZ8V7yFobaVejAN7sMG39iiC5BmFk7b1NB1NNYcrEu1Go
executed transaction: 51d45916fa252e...  200 bytes  194 us
# eosio <= eosio::newaccount            {"creator":"eosio","name":"bob","owner":{"threshold":1,"keys":[{"key":"EOS7cX17CZ8V7yFobaVejAN7sMG39...


Давайте перейдем к созданию шифрования / дешифрования сообщения и взаимодействия со смарт-контрактом для пользователя.


  • Создайте приватный ключ и запишите в файл.
config.set_default_curve(SECP256K1)
private_key = keys.UmbralPrivateKey.gen_key()
f = open('priv.key', 'wb')
f.write(private_key.to_bytes())
f.close()


  • Сконструируйте синтаксический анализатор.
   parser = argparse.ArgumentParser(description = 'messenger')
   parser.add_argument('--private-key-file', type = str, dest = 'private_key_file', required = False, help = 'Path to the private key file.')
   parser.add_argument('--send-msg-id', type = str, dest = 'send_msg_id', required = False, help = 'Send a message, msg_id')
   parser.add_argument('--send-msg-from', type = str, dest = 'send_msg_from', required = False, help = 'Send a message, from which EOS account')
   parser.add_argument('--send-msg-to', type = str, dest = 'send_msg_to', required = False, help = 'Send a message, to which EOS account')
   parser.add_argument('--send-msg', type = str, dest = 'send_msg', required = False, help = 'Message to be sent')
   parser.add_argument('--read-msg-to', type = str, dest = 'read_msg_to', required = False, help = 'Read a message, to which EOS account')
   return parser
parser = create_parser()
args = parser.parse_args(argv)


  • Прочтите файл privkey.
   if os.path.exists(privkey_file):
       with open(privkey_file, 'rb') as f:
           try:
               privkey = f.read()
           except Exception as e:
               print("Cannot read: {}".format(e))
               sys.exit(1)
           f.close()
           return privkey
   else:
       print('Cannot find file: {}'.format(privkey_file))
       sys.exit(1)


  • Зашифруйте сообщение и отправьте его.
   privkey_bytes = read_privkey_file(private_key_file)
   privkey = keys.UmbralPrivateKey.from_bytes(privkey_bytes)
   pubkey = privkey.get_pubkey()
   plaintext = msg.encode()
   ciphertext, capsule = pre.encrypt(pubkey, plaintext)
   data = '{"from":"' + send_msg_from + '", "to":"' + send_msg_to + '", "msg_id":"' + send_msg_id + '", "ciphertext": "' + ciphertext.hex() + '", "capsule": "' + capsule.to_bytes().hex() + '"}'
   subprocess.call(['cleos', 'push', 'action', DEFAULT_ACCOUNT, 'sendmsg', data , '-p', send_msg_from])


  • Прочитайте из messages таблицы, если to совпадения read_msg_to, расшифруйте сообщение и затем удалите его.
   privkey_bytes = read_privkey_file(private_key_file)
   privkey = keys.UmbralPrivateKey.from_bytes(privkey_bytes)
  
   payload = '{"scope":"' + DEFAULT_ACCOUNT + '","code":"' + DEFAULT_ACCOUNT + '","table": "' + DEFAULT_TABLE+ '", "json":"true"}'
   response = requests.request("POST", DEFAULT_URL, data=payload)  
  
   found = False
   for msg in response.json()['rows']:
       if msg['to'] == read_msg_to:
           ciphertext = msg['ciphertext']
           capsule = msg['capsule']
           msg_id = msg['msg_id']
           found = True
           break
   if found:       
       capule = pre.Capsule.from_bytes(bytes.fromhex(capsule), privkey.params)
       cleartext = pre.decrypt(
                         ciphertext = bytes.fromhex(ciphertext),
                         capsule = capule,
                         decrypting_key = privkey)
       print('Cleartext: {}'.format(cleartext))
       print('Deleting msg_id: {}'.format(msg_id))
       data = '{"to":"' + read_msg_to + '", "msg_id":"' + str(msg_id) + '"}'
       subprocess.call(['cleos', 'push', 'action', DEFAULT_ACCOUNT, 'deletemsg', data , '-p', read_msg_to])


  • Значения по умолчанию.
DEFAULT_TABLE = 'messages'
DEFAULT_URL= "http://127.0.0.1:8888/v1/chain/get_table_rows"


Давайте завершим их и протестируем!

executed transaction: dfe17144e105c54d192...  392 bytes  648 us
#         queue <= queue::sendmsg               {"from":"alice","to":"bob","msg_id":1,"ciphertext":"8c53a656c9...


Проверьте messages таблицу.

{
 "rows": [{
     "msg_id": 1,
     "from": "alice",
     "to": "bob",
     "ciphertext": "8c8aa24196152b53da35d9fbf9e3c4d8e10f6b7153a656c9921cb440cc69a782c2ba0c2cf2",
     "capsule": "028c4e8279c0919bdec4ea98b4251f15a74868d2ea7554ab796230af8f88e62cd9031c07e90c6183152e140c43a370f2c12526b6d62269f8673a35e6a19fc6ff78ac2f3a28dbed868858ec71228644f277c8ecfb691aa41dab863072e6f39c55d294"
   }
 ],
 "more": false
}


Зашифрованное сообщение есть. Тогда давайте прочитаем.

Cleartext: b'hello,bob'
Deleting msg_id: 1
executed transaction: 6cdad7694f3fe6c8...112 bytes  566 us
#         queue <= queue::deletemsg    {"to":"bob","msg_id":1}


Проверьте messages таблицу, сообщение исчезло.

{
 "rows": [],
 "more": false
}


Таким образом, мы изучили, как защищать сообщения от EOS. Двигаясь вперед, мы можем работать над сценарием, где у Алисы и Боба есть свои собственные ключи, или отправлять сообщения нескольким пользователям.

Перевод CryptoLions

photo_122x122.jpg

Website

Telegram

Steemit

Twitter

GitHub

Meetup