分类于: 嵌入式
关键词: Repchain

Protobuf 构建

根据 RCJava 的 dev_sdk_preview 分支 src/main/resources 目录下的 peer.proto 文件, 利用 protobuf-c 生成针对 peer.proto 的 peer.pb-c.c 文件。

由于在 peer.proto 文件中:

/*
* 交易
*/
message Transaction {
    string id = 1;
    enum Type {
        UNDEFINED = 0;
        // deploy a chaincode to the network and call `Init` function
        CHAINCODE_DEPLOY = 1;
        // call a chaincode `Invoke` function as a transaction
        CHAINCODE_INVOKE = 2;
        CHAINCODE_SET_STATE = 3;
    }
    Type type = 2;
    //store ChaincodeID as bytes so its encrypted value can be stored
    ChaincodeId cid = 3;
    oneof para {
        ChaincodeDeploy spec = 4;
        ChaincodeInput ipt = 5;
        bool state = 6;
    }
    Signature signature = 7;
}

其中的:

oneof para {
  ChaincodeDeploy spec = 4;
  ChaincodeInput ipt = 5;
  bool state = 6;
}
Signature signatrue = 7;

在 protobuf-c 中,会生成一个 Uion 的 c 语言联合体,考虑到运行的环境是嵌入式实时操作系统,将此处的代码改为:

message Transaction
{
  string id = 1;

  enum Type 
  {
    UNDEFINED = 0;
    CHAINCODE_DEPLOY = 1;
    CHAINCODE_INVOKE = 2;
    CHAINCODE_SET_STATE = 3;
  }
  Type type = 2;

  ChaincodeId cid = 3;
  ChaincodeInput ipt = 5;

  Signature signature = 7;
}

PS: 此处的 cid, ipt, signature 的数值应该与 peer.proto 中定义的消息类型一致。否则在 protobuf 解析是会出现错误,导致服务器无法对上传的 Transaction 的 protobuf 消息解码。

签名算法错误问题

RCJava 中对数据签名使用的默认算法是 SHA1withECDSA ,使用的秘钥是由 keystore.exe 使用 SHA256withECDSA 算法生成,注意在对数据签名时使用正确的算法。

在使用 SHA1withECDSA 与 SHA256withECDSA 时需要注意, SHA1withECDSA 算法是先采用 SHA1 对加密的消息进行 Hash 一共是 160 bits(20 bytes), SHA256withECDSA 对消息进行 hash 是 256 bits(32 bytes)。

调试过程中,一开始采用的是 SHA256withECDSA 算法对消息进行签名:

if (0 == mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), pBuffer, pBufferSize, digest))
{
  LOG_I("get the hash of the protobuf succeed!");
  rt_kprintf("\r\n");
  for (size_t i = 0; i < sizeof digest; i++)
  {
    rt_kprintf("%s%02X%s", i % 16 == 0 ? "\n\t":" ", digest[i], i == sizeof(digest) - 1 ? "\n":"");
  }
  rt_kprintf("\r\n");
}
else
{
  LOG_E("get the hash of the protobuf failed!");
}

if (0 == mbedtls_pk_sign(&pk_ctx, MBEDTLS_MD_SHA256, digest, sizeof digest, sig, &sigCnt, mbedtls_entropy_func, NULL))
{
  LOG_I("sign the data succeed!");
}
else
{
  LOG_E("sign the data failed!");
}

经过确认,更改签名算法为 SHA256withECDSA :

if (0 == mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA1), pBuffer, pBufferSize, digest))
{
  LOG_I("get the hash of the protobuf succeed!");
  rt_kprintf("\r\n");
  for (size_t i = 0; i < sizeof digest; i++)
  {
    rt_kprintf("%s%02X%s", i % 16 == 0 ? "\n\t":" ", digest[i], i == sizeof(digest) - 1 ? "\n":"");
  }
  rt_kprintf("\r\n");
}
else
{
  LOG_E("get the hash of the protobuf failed!");
}

if (0 == mbedtls_pk_sign(&pk_ctx, MBEDTLS_MD_SHA1, digest, sizeof digest, sig, &sigCnt, mbedtls_entropy_func, NULL))
{
  LOG_I("sign the data succeed!");
}
else
{
  LOG_E("sign the data failed!");
}

注意:在更改签名算法后,需要更改 mbedlts_pk_sign 中 digest 数组的上界,由于 sizeof digest 是默认数组上界的,不更改数组上界会导致数据签名是的 digest 消息错误,最后导致数据签名校验失败。