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

in eos •  6 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

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!