EOS 數據簽名與公匙驗證代碼用例


  本文編寫了一個小例子詮釋了EOS是如何對數據簽名與校驗的,通過本文可以理解了簽名的重要性和數據的不可篡改性。

  系統: ubuntu  版本為EOS1.1.1

      注:因為本文的程序是把EOS里面的錢包和fc工具的代碼全部提取出來編譯的,這個過程相對復雜本文不做解釋,這里只注重本文的內容,但我的示例代碼是來自於此用例的片段。

 

一.測試代碼

std::string dig_str("test");

public_key_type pubk(std::string("EOS62M5kVouCEU31xP736Txb4pe82FoncprqevPuagE6boCLxwsC8")); import_key("5KT27tqC9YgfEyqD61EjCFRz7QXTz8XrYadzZ8LAGt7HVovUHnT");
fc::crypto::signature sig_stru
= sign_digest(dig, pubk);
unsigned
char arr_sign[200]; unsigned char arr_pubkey[100]; memset(arr_sign, 0, sizeof(arr_sign)); memset(arr_pubkey, 0, sizeof(arr_pubkey)); fc::datastream<const unsigned char*> ds_sign( arr_sign, 200 ); fc::raw::pack( ds_sign, sig_stru); int siglen = ds_sign.tellp();

  std::cout << std::string(dig) << std::endl;
  std::cout << std::endl;

 
         

  std::cout << std::string(sig_stru) << std::endl;
  std::cout << std::endl;


fc::datastream<const unsigned char*> ds_pub( arr_pubkey, 100 );
for(int i = 0; i < siglen; ++i) { printf("%02x", arr_sign[i]); } std::cout << std::endl; fc::raw::pack( ds_pub, pubk); int publen=ds_pub.tellp(); for(int i = 0; i < publen; ++i) { printf("%02x", arr_pubkey[i]); } std::cout << std::endl; assert_recover_key( dig, arr_sign , siglen,arr_pubkey, publen );

 

代碼運行的結果如下:

9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08

SIG_K1_KkSbKuDSV7x87FeexJ3goinHsd3MhPBCH91MRqhyS3Z7H1v4HtUZoJc6AkgYWW5mEan7UbdmDAzDpCzUwheDPxRxtzuD8s

002077f62e26587bd9345c61cf1904f048b1e2cd252acae79d3c1e6f48a4aef9bd03778ae7498014e9207e35117cf79920b2e31becb7e24d6c09ebeaf184c956c81c

000295898b10fe9f5f056ed09e334e8e768e42cc16c1a2e02565de6d57b5e25cfd55

 

二.代碼分析

1.數據發送端

首先,我們對字符串"test"形成摘要,摘要轉換成字符串為:

9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08

然后再對摘要使用私匙簽名,轉換成字符串形式輸出如下:

SIG_K1_KkSbKuDSV7x87FeexJ3goinHsd3MhPBCH91MRqhyS3Z7H1v4HtUZoJc6AkgYWW5mEan7UbdmDAzDpCzUwheDPxRxtzuD8s

但實際上上面的數據存在於arr_sign中的數據(對應的datastream也可),我這里按字節打印成十六進制是如下格式的:

002077f62e26587bd9345c61cf1904f048b1e2cd252acae79d3c1e6f48a4aef9bd03778ae7498014e9207e35117cf79920b2e31becb7e24d6c09ebeaf184c956c81c

到這里我們得到了數據test內容的簽名,那么發送數據方就可以使用明文test再加上簽名進行發送給對端,簽名一般使用十六進制。

 

2.數據接收端

在上面的用例中,我們直接調用EOS即assert_recover_key就可得到驗證,那么如何是在合約中呢?

 

如果數據在合約中驗證,我們需要三個字段:發送的明文+簽名+用戶公匙

明文就是test,簽名就是 002077f62e26587bd9345c61cf1904f048b1e2cd252acae79d3c1e6f48a4aef9bd03778ae7498014e9207e35117cf79920b2e31becb7e24d6c09ebeaf184c956c81c

公匙就是000295898b10fe9f5f056ed09e334e8e768e42cc16c1a2e02565de6d57b5e25cfd55,而不是EOS62M5kVouCEU31xP736Txb4pe82FoncprqevPuagE6boCLxwsC8,其實這么說不准確,只是前者是以十六進制體現出來的。

現在接收端收到的內容是:test + 002077f62e26587bd9345c61cf1904f048b1e2cd252acae79d3c1e6f48a4aef9bd03778ae7498014e9207e35117cf79920b2e31becb7e24d6c09ebeaf184c956c81c

(用戶的公匙理論上是接收方本來就知道的)

那么現在合約中代碼就只需要轉換一下格式即可:

 1 struct sig_hash_key {
 2          transaction_id_type dig;
 3          public_key pk;
 4          signature sig;
 5  };
 6 
 7 sig_hash_key sh;
 8 public_key pk;
 9 
10 sha256(const_cast<char*>(userdata.data()),userdata.length(), &sh.dig);
11 
12 from_hex( sig, (char*)sh.sig.data, sig.length() );
13 from_hex( pubk, sh.pk.data, pubk.length());
14 
15 assert_recover_key( &sh.dig,  (const char*)&sh.sig, sizeof(sh.sig), sh.pk.data, sizeof(sh.pk) );

 

下面是一個將十六進制字符串轉換成字符數組的函數,來自於fc工具中,加上去即可。

 1 size_t from_hex( const std::string& hex_str, char* out_data, size_t out_data_len ) {
 2         std::string::const_iterator i = hex_str.begin();
 3         uint8_t* out_pos = (uint8_t*)out_data;
 4         uint8_t* out_end = out_pos + out_data_len;
 5         while( i != hex_str.end() && out_end != out_pos ) {
 6           *out_pos = from_hex( *i ) << 4;
 7           ++i;
 8           if( i != hex_str.end() )  {
 9               *out_pos |= from_hex( *i );
10               ++i;
11           }
12           ++out_pos;
13         }
14         return out_pos - (uint8_t*)out_data;
15     }
16 
17 
18 uint8_t from_hex( char c ) {
19       if( c >= '0' && c <= '9' )
20         return c - '0';
21       if( c >= 'a' && c <= 'f' )
22           return c - 'a' + 10;
23       if( c >= 'A' && c <= 'F' )
24           return c - 'A' + 10;
25 
26         eosio_assert( false, " invalid char \n");
27         return 0;
28     }

 

到此為即,我們實現了數據的簽名驗證,也可以將此功能加在其它項目中以增加數據的安全性。

 
        

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM