SDK 使用指南

使用 C3S 服务,首先您需要通过编写 WASM 智能合约将业务逻辑写成可信计算应用 TAPP。TAPP 编写完成后,需要使用 MYCDT 编译工具将 TAPP 编译成 WASM 字节码。之后,通过 MYTF SDK 将 TAPP 安装上传至 MYTF 可信计算引擎中。最后,通过调用 TAPP 接口来执行 TAPP并获得执行结果。本文仅介绍如何使用 SDK 调用 TAPP ,并提供相应的示例代码以供参考。有关如何编写 TAPP,具体参考 可信计算应用开发

调用可信计算应用分为以下四步:

搭建开发环境

使用 SDK 首先需要配置开发环境依赖,请检查并配置以下四项依赖:

  • JDK 1.8 及以上版本,可在终端运行 java -version 查看当前 Java 版本。
  • Maven 3.5.4 及以上版本,在终端运行 mvn -v 查看当前 Maven 版本。
  • Java 运行环境需要支持 BouncyCastle。
  • 引用 SDK jar 包并配置 SDK 间接依赖。

SDK 间接依赖如下所示:

  1. <dependency>
  2. <groupId>org.apache.httpcomponents</groupId>
  3. <artifactId>httpclient</artifactId>
  4. <version>4.5.2</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.apache.commons</groupId>
  8. <artifactId>commons-lang3</artifactId>
  9. <version>3.5</version>
  10. </dependency>
  11. <dependency>
  12. <groupId>org.bouncycastle</groupId>
  13. <artifactId>bcpkix-jdk15on</artifactId>
  14. <version>1.61</version>
  15. </dependency>
  16. <dependency>
  17. <groupId>com.alibaba</groupId>
  18. <artifactId>fastjson</artifactId>
  19. <version>1.2.56.sec08</version>
  20. </dependency>

初始化配置信息

  • 访问秘钥

您可以获取阿里云账号的访问密钥(包括AccessKey ID 和 AccessKey Secret),用于 C3S 接口的访问。

  1. // 模拟用户 accessId 和 accessPrivateKey
  2. String userAccessId = "A...L";
  3. String userAccessPrivateKey = "z...x";
  • 配置信息
  1. AliCloudClientConfig config = new AliCloudClientConfig();
  2. config.setAccessId(accessId);
  3. config.setAccessPrivateKey(accessPrivateKey);
  4. config.setMytfTrustLevel(0);
  5. // 选填,使用数据授权特性和可升级 TAPP 特性时需要,需要自己生成秘钥并用密码加密
  6. // 用户身份秘钥绑定的 DID 标识
  7. config.setIdentityPrivateKeyDIDIndex(userDID);
  8. // 用户身份秘钥,输入被加密的私钥全文
  9. config.setIdentityPrivateKey(userIdentityPriKey);
  10. // 用户身份秘钥的加密密码
  11. config.setIdentityPrivateKeyPW(password);
  12. // 选填, SecretPrivateKey 用来保证用户请求时的端到端加密,如果不填客户端会自动生成
  13. // 若自动生成,则在 sdk 重启时会被丢弃,可能会导致之前的请求结果无法解密。请注意此问题。
  14. // 用户加密秘钥,输入被加密的私钥全文
  15. config.setSecretPrivateKey(userSecretPriKey);
  16. // 用户加密秘钥的加密密码
  17. config.setSecretPrivateKeyPW(password2);
  • IAS 根证书
  1. String trustedIASCert = "-----BEGIN CERTIFICATE-----\n"
  2. + "MIIFSzCCA7OgAwIBAgIJANEHdl0yo7CUMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNV\n"
  3. + "BAYTAlVTMQswCQYDVQQIDAJDQTEUMBIGA1UEBwwLU2FudGEgQ2xhcmExGjAYBgNV\n"
  4. + "BAoMEUludGVsIENvcnBvcmF0aW9uMTAwLgYDVQQDDCdJbnRlbCBTR1ggQXR0ZXN0\n"
  5. + "YXRpb24gUmVwb3J0IFNpZ25pbmcgQ0EwIBcNMTYxMTE0MTUzNzMxWhgPMjA0OTEy\n"
  6. + "MzEyMzU5NTlaMH4xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEUMBIGA1UEBwwL\n"
  7. + "U2FudGEgQ2xhcmExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0aW9uMTAwLgYDVQQD\n"
  8. + "DCdJbnRlbCBTR1ggQXR0ZXN0YXRpb24gUmVwb3J0IFNpZ25pbmcgQ0EwggGiMA0G\n"
  9. + "CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCfPGR+tXc8u1EtJzLA10Feu1Wg+p7e\n"
  10. + "LmSRmeaCHbkQ1TF3Nwl3RmpqXkeGzNLd69QUnWovYyVSndEMyYc3sHecGgfinEeh\n"
  11. + "rgBJSEdsSJ9FpaFdesjsxqzGRa20PYdnnfWcCTvFoulpbFR4VBuXnnVLVzkUvlXT\n"
  12. + "L/TAnd8nIZk0zZkFJ7P5LtePvykkar7LcSQO85wtcQe0R1Raf/sQ6wYKaKmFgCGe\n"
  13. + "NpEJUmg4ktal4qgIAxk+QHUxQE42sxViN5mqglB0QJdUot/o9a/V/mMeH8KvOAiQ\n"
  14. + "byinkNndn+Bgk5sSV5DFgF0DffVqmVMblt5p3jPtImzBIH0QQrXJq39AT8cRwP5H\n"
  15. + "afuVeLHcDsRp6hol4P+ZFIhu8mmbI1u0hH3W/0C2BuYXB5PC+5izFFh/nP0lc2Lf\n"
  16. + "6rELO9LZdnOhpL1ExFOq9H/B8tPQ84T3Sgb4nAifDabNt/zu6MmCGo5U8lwEFtGM\n"
  17. + "RoOaX4AS+909x00lYnmtwsDVWv9vBiJCXRsCAwEAAaOByTCBxjBgBgNVHR8EWTBX\n"
  18. + "MFWgU6BRhk9odHRwOi8vdHJ1c3RlZHNlcnZpY2VzLmludGVsLmNvbS9jb250ZW50\n"
  19. + "L0NSTC9TR1gvQXR0ZXN0YXRpb25SZXBvcnRTaWduaW5nQ0EuY3JsMB0GA1UdDgQW\n"
  20. + "BBR4Q3t2pn680K9+QjfrNXw7hwFRPDAfBgNVHSMEGDAWgBR4Q3t2pn680K9+Qjfr\n"
  21. + "NXw7hwFRPDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkq\n"
  22. + "hkiG9w0BAQsFAAOCAYEAeF8tYMXICvQqeXYQITkV2oLJsp6J4JAqJabHWxYJHGir\n"
  23. + "IEqucRiJSSx+HjIJEUVaj8E0QjEud6Y5lNmXlcjqRXaCPOqK0eGRz6hi+ripMtPZ\n"
  24. + "sFNaBwLQVV905SDjAzDzNIDnrcnXyB4gcDFCvwDFKKgLRjOB/WAqgscDUoGq5ZVi\n"
  25. + "zLUzTqiQPmULAQaB9c6Oti6snEFJiCQ67JLyW/E83/frzCmO5Ru6WjU4tmsmy8Ra\n"
  26. + "Ud4APK0wZTGtfPXU7w+IBdG5Ez0kE1qzxGQaL4gINJ1zMyleDnbuS8UicjJijvqA\n"
  27. + "152Sq049ESDz+1rRGc2NVEqh1KaGXmtXvqxXcTB+Ljy5Bw2ke0v8iGngFBPqCTVB\n"
  28. + "3op5KBG3RjbF6RRSzwzuWfL7QErNC8WEy5yDVARzTA5+xmBc388v9Dm21HGfcC8O\n"
  29. + "DD+gT9sSpssq0ascmvH49MOgjt1yoysLtdCtJW/9FZpoOypaHx0R+mJTLwPXVMrv\n"
  30. + "DaVzWh5aiEx+idkSGMnX\n"
  31. + "-----END CERTIFICATE-----";

安装可信应用

安装 TAPP 会将 TAPP 字节码部署到 MYTF 可信计算引擎中,用户需要指定 TappId 和 TappVersion 来唯一标识 TAPP。

  1. // 启动client会获取 C3S 平台信息,安装和执行 TAPP 前必须要调用 startup() 接口
  2. AliCloudMytfClient client = new AliCloudMytfClient(config);
  3. Boolean ifSuccess = client.startup();
  4. Assert.assertTrue(ifSuccess);
  5. // 获取 MYTFInfo 信息
  6. MYTFInfo mytfInfo = client.getMYTFInfo();
  7. Assert.assertNotNull(mytfInfo);
  8. // 安装 TAPP 前,准备 TAPP 信息,TEST_CONTRACT_FILE 为编译后的 TAPP 文件路径
  9. String tappId = "example"+ new Random().nextInt(1000000);
  10. Integer tappVersion = 2;
  11. byte[] bytecodes = FileUtils.readFileToByteArray(new File(TEST_CONTRACT_FILE));
  12. // 构造安装 TAPP 请求
  13. TappInstallRequest tappInstallRequest = TappInstallRequest.builder()
  14. .newTapp(tappId, tappVersion, bytecodes)
  15. .build();
  16. // 发送安装 TAPP 请求
  17. TappInstallResponse tappInstallResponse = client.installTapp(tappInstallRequest);
  18. System.out.println(tappInstallResponse);
  19. Assert.assertTrue(tappInstallResponse.isSuccess());
  20. // 查询 安装过的 TAPP 信息并保存在本地,执行 TAPP 前必须要调用 getTappInfo() 接口
  21. TappInfo tappInfo = client.getTappInfo(tappId, tappVersion);
  22. Assert.assertNotNull(tappInfo);

执行可信应用

下面是使用 SDK 执行可信应用开发的参考示例,您可根据实际业务需求参考该示例进行开发。

普通执行请求

  • TAPP 接口示例
  1. INTERFACE std::string TestSayHi() {
  2. return "hi";
  3. }
  4. INTERFACE std::string TestRepeat(const std::string& msg) {
  5. return msg;
  6. }
  7. INTERFACE uint32_t TestAdd(const uint32_t& num1, const uint32_t& num2) {
  8. return num1 + num2;
  9. }
  10. INTERFACE std::vector<std::string> TestStringVector(const std::string& data) {
  11. std::vector<std::string> ret;
  12. int err_code = 2;
  13. ret.push_back("OK");
  14. ret.push_back("FAIL");
  15. ret.push_back(data);
  16. ret.push_back(std::to_string(err_code));
  17. return ret;
  18. }
  19. INTERFACE std::string TestOutput(const std::string& data) {
  20. std::string log_buffer = "log buffer";
  21. log_buffer.append("1234");
  22. log_buffer.append("abc");
  23. Require(false, log_buffer.c_str());
  24. return data;
  25. }
  • SDK 使用示例
  1. // 构造 TAPP 执行合约接口"TestSayHi",调用无参数的 TAPP 接口
  2. String testReqMethod = "TestSayHi";
  3. TappExecuteRequest tappExecuteRequest = TappExecuteRequest.builder()
  4. .defaultRequest(tappId, tappVersion, testReqMethod)
  5. .build();
  6. // 发送 TAPP 执行请求
  7. TappExecuteResponse tappExecuteResponse = client.executeTapp(tappExecuteRequest);
  8. // 解析 TAPP 执行结果
  9. Assert.assertTrue(tappExecuteResponse.isRequestSuccess());
  10. Assert.assertTrue(tappExecuteResponse.isExecuteSuccess());
  11. System.out.println("result : " + tappExecuteResponse.getReturnValue().toUtf8String());
  12. // 构造 TAPP 执行合约接口"TestAdd",调用有参数的 TAPP 接口
  13. testReqMethod = "TestAdd";
  14. tappExecuteRequest = TappExecuteRequest.builder()
  15. .defaultRequest(tappId, tappVersion, testReqMethod)
  16. .addUint32(BigInteger.valueOf(12))
  17. .addUint32(BigInteger.valueOf(11))
  18. .build();
  19. // 发送 TAPP 执行请求
  20. tappExecuteResponse = client.executeTapp(tappExecuteRequest);
  21. // 解析 TAPP 执行结果
  22. Assert.assertTrue(tappExecuteResponse.isRequestSuccess());
  23. Assert.assertTrue(tappExecuteResponse.isExecuteSuccess());
  24. System.out.println("result : " + tappExecuteResponse.getReturnValue().toUint32());
  25. // 构造 TAPP 执行合约接口"TestStringVector",调用有参数的 TAPP 接口
  26. testReqMethod = "TestStringVector";
  27. tappExecuteRequest = TappExecuteRequest.builder()
  28. .defaultRequest(tappId, tappVersion, testReqMethod)
  29. .addString("{hello mytf!}")
  30. .build();
  31. // 发送 TAPP 执行请求
  32. tappExecuteResponse = client.executeTapp(tappExecuteRequest);
  33. // 解析 TAPP 执行结果
  34. Assert.assertTrue(tappExecuteResponse.isRequestSuccess());
  35. Assert.assertTrue(tappExecuteResponse.isExecuteSuccess());
  36. System.out.println("result : " + tappExecuteResponse.getReturnValue().toUtf8StringList().toString());
  37. // 构造 TAPP 执行合约接口"TestOutput",调用有参数的 TAPP 接口
  38. String testOutputData = "abc";
  39. testReqMethod = "TestOutput";
  40. tappExecuteRequest = TappExecuteRequest.builder()
  41. .defaultRequest(tappId, tappVersion, testReqMethod)
  42. .addString(testOutputData)
  43. .build();
  44. // 发送 TAPP 执行请求
  45. tappExecuteResponse = client.executeTapp(tappExecuteRequest);
  46. // 执行 TAPP 异常,查看执行异常信息
  47. System.out.println("responseCode: " + tappExecuteResponse.getResponseCode());
  48. System.out.println("output: " + tappExecuteResponse.getOutputString());

端到端加密请求

用户提交可信计算执行任务时,可以选择端到端加密发送。SDK 会将用户在本地构造的执行请求通过 ECIES 算法进行加密,并将加密后的请求发送给 MYTF。MYTF 接收到请求后会在可信执行环境内将密文解密并进行计算。计算完成后,MYTF 将结果同样通过 ECIES 算法加密并返回给客户端,客户端在本地解密密文获得计算结果,通过这种方式实现全链路隐私保护。

c3s.002

  • SDK 使用示例
  1. // 构造执行 TAPP 请求
  2. testReqMethod = "TestRepeat";
  3. tappExecuteRequest = TappExecuteRequest.builder()
  4. .defaultRequest(tappId, tappVersion, testReqMethod)
  5. .addString("hello mytf!")
  6. .build();
  7. // 发送端到端加密的执行请求
  8. tappExecuteResponse = client.executeTappPrivately(tappExecuteRequest);
  9. // 检查是否执行成功
  10. Assert.assertNotNull(tappExecuteResponse);
  11. Assert.assertTrue(tappExecuteResponse.isRequestSuccess());
  12. Assert.assertTrue(tappExecuteResponse.isExecuteSuccess());
  13. // 获取执行结果
  14. Assert.assertEquals("hello mytf!", tappExecuteResponse.getReturnValue().toUtf8String());

格式转换工具

  • TAPP 接口示例
  1. // 使用 rapidjson 第三方库对 json 进行构造和解析
  2. INTERFACE std::string TestJson() {
  3. using namespace::rapidjson;
  4. std::vector<std::string> ret;
  5. std::string stringFromStream = R"({
  6. "dictVersion": 1,
  7. "content":
  8. [
  9. {"key": "word1", "value": "单词1"} ,
  10. {"key": "word2", "value": "单词2"} ,
  11. {"key": "word5", "value": "单词3"}
  12. ]
  13. })";
  14. // ---------------------------- read json --------------------
  15. // parse json from string.
  16. using rapidjson::Document;
  17. Document doc;
  18. doc.Parse<0>(stringFromStream.c_str());
  19. if (doc.HasParseError()) {
  20. rapidjson::ParseErrorCode code = doc.GetParseError();
  21. Require(code == kParseErrorNone, "parse from string");
  22. }
  23. // use values in parse result.
  24. using rapidjson::Value;
  25. Value& v = doc["dictVersion"];
  26. if (v.IsInt()) {
  27. print("%d\n", v.GetInt());
  28. }
  29. Value& contents = doc["content"];
  30. if (contents.IsArray()) {
  31. for (size_t i = 0; i < contents.Size(); ++i) {
  32. Value& v = contents[i];
  33. Require(v.IsObject(), "parse error");
  34. if (v.HasMember("key") && v["key"].IsString()) {
  35. print("%s\n", v["key"].GetString());
  36. }
  37. if (v.HasMember("value") && v["value"].IsString()) {
  38. print("%s\n", v["value"].GetString());
  39. }
  40. }
  41. }
  42. // ---------------------------- write json --------------------
  43. print("add a value into array\n");
  44. Value item(Type::kObjectType);
  45. item.AddMember("key", "word2", doc.GetAllocator());
  46. item.AddMember("value", "单词2", doc.GetAllocator());
  47. contents.PushBack(item, doc.GetAllocator());
  48. // convert dom to string.
  49. StringBuffer buffer; // in rapidjson/stringbuffer.h
  50. Writer<StringBuffer> writer(buffer); // in rapidjson/writer.h
  51. doc.Accept(writer);
  52. print("%s\n", buffer.GetString());
  53. ret.push_back(buffer.GetString());
  54. // ---------------------------- add member to new json --------------------
  55. rapidjson::Document doc1;
  56. doc1.SetObject();
  57. rapidjson::Document::AllocatorType &allocator = doc1.GetAllocator();
  58. rapidjson::Value data_a_json;
  59. rapidjson::Value data_b_json;
  60. std::string a = "abc";
  61. std::string b = "bcd";
  62. data_a_json.SetString(a.c_str(), (int) a.size(), allocator);
  63. data_b_json.SetString(b.c_str(), (int) b.size(), allocator);
  64. doc1.AddMember("new_member_a", data_a_json, allocator);
  65. doc1.AddMember("new_member_b", data_a_json, allocator);
  66. // add item to array
  67. rapidjson::Value items(rapidjson::kArrayType);
  68. int item_count = 10;
  69. std::string item = "cde";
  70. for(int i = 0; i < item_count; ++i) {
  71. rapidjson::Value value;
  72. value.SetString(item.c_str(), item.length(), allocator);
  73. items.PushBack(value, allocator);
  74. }
  75. doc1.AddMember("items", items, allocator);
  76. StringBuffer buffer2;
  77. Writer<StringBuffer> writer2(buffer2);
  78. doc1.Accept(writer2);
  79. ret.push_back(buffer2.GetString().c_str());
  80. ret.push_back("OK");
  81. return ret;
  82. }
  83. INTERFACE std::string TestBase64Encode(std::string data) {
  84. std::string out;
  85. CryptoErrorCode err = Base64Encode(data, out);
  86. if (err != CryptoErrorCode::kSuccess) {
  87. print("failed to base64encode: %d", err);
  88. return std::to_string(err);
  89. }
  90. return out;
  91. }
  92. INTERFACE std::string TestBase64Decode(std::string data) {
  93. std::string out;
  94. CryptoErrorCode err = Base64Decode(data, out);
  95. if (err != CryptoErrorCode::kSuccess) {
  96. print("failed to base64decode: %d", err);
  97. return std::to_string(err);
  98. }
  99. return out;
  100. }
  • SDK 使用示例
  1. // 测试Base64编码解码
  2. // 构造执行 TAPP 请求,调用 TAPP 接口 "TestBase64Encode"
  3. String plaindata = "this is test for Base64Encode & Base64Decode";
  4. testReqMethod = "TestBase64Encode";
  5. tappExecuteRequest = TappExecuteRequest.builder()
  6. .defaultRequest(tappId, tappVersion, testReqMethod)
  7. .addString(plaindata)
  8. .build();
  9. // 发送 TAPP 执行请求
  10. tappExecuteResponse = client.executeTapp(tappExecuteRequest);
  11. // 解析 TAPP 执行结果
  12. Assert.assertTrue(tappExecuteResponse.isRequestSuccess());
  13. Assert.assertTrue(tappExecuteResponse.isExecuteSuccess());
  14. String base64String = tappExecuteResponse.getReturnValue().toUtf8String();
  15. System.out.println("plaindata: " + new String(Base64.decode(base64String)));
  16. // 构造执行 TAPP 请求,调用 TAPP 接口 "TestBase64Decode"
  17. testReqMethod = "TestBase64Decode";
  18. tappExecuteRequest = TappExecuteRequest.builder()
  19. .defaultRequest(tappId, tappVersion, testReqMethod)
  20. .addString(base64String)
  21. .build();
  22. // 发送 TAPP 执行请求
  23. tappExecuteResponse = client.executeTapp(tappExecuteRequest);
  24. // 解析 TAPP 执行结果
  25. Assert.assertTrue(tappExecuteResponse.isRequestSuccess());
  26. Assert.assertTrue(tappExecuteResponse.isExecuteSuccess());
  27. System.out.println("plaindata: " + tappExecuteResponse.getReturnValue().toUtf8String());

散列函数

  • TAPP 接口示例
  1. INTERFACE std::vector<std::string> TestHash(std::string msg) {
  2. std::vector<std::string> result;
  3. std::string sha256hash;
  4. CryptoErrorCode err = Sha256(msg, sha256hash);
  5. if (err != CryptoErrorCode::kSuccess) {
  6. print("failed to sha256: %d", err);
  7. result.push_back(std::to_string(err));
  8. return result;
  9. }
  10. result.push_back(Bin2Hex(sha256hash));
  11. std::string sm3hash;
  12. err = Sm3_256(msg, sm3hash);
  13. if (err != CryptoErrorCode::kSuccess) {
  14. print("failed to SM3_256: %d", err);
  15. result.push_back(std::to_string(err));
  16. return result;
  17. }
  18. print("sm3_256 hash: %s", Bin2Hex(sm3hash).c_str());
  19. result.push_back(Bin2Hex(sm3hash));
  20. return result;
  21. }
  22. INTERFACE std::vector<std::string> TestHMAC(std::string msg, std::string secret) {
  23. std::vector<std::string> result;
  24. std::string hmac_sha256_out;
  25. CryptoErrorCode err = Hmac(MdType::kSha256, msg, secret, hmac_sha256_out);
  26. if (err != CryptoErrorCode::kSuccess) {
  27. print("failed to do hmac: %d", err);
  28. result.push_back(std::to_string(err));
  29. return result;
  30. }
  31. result.push_back(Bin2Hex(hmac_sha256_out));
  32. std::string hmac_sha1_out;
  33. err = Hmac(MdType::kSha1, msg, secret, hmac_sha1_out);
  34. if (err != CryptoErrorCode::kSuccess) {
  35. print("failed to do hmac: %d", err);
  36. result.push_back(std::to_string(err));
  37. return result;
  38. }
  39. result.push_back(Bin2Hex(hmac_sha1_out));
  40. return result;
  41. }
  • SDK 使用示例
  1. // 测试哈希算法
  2. // 本地计算Sha256hash和Sm3hash
  3. String plaindata = "this is test for hash";
  4. byte[] expectedSha256hash = Hash.sha256(plaindata.getBytes());
  5. byte[] expectedSm3hash = Hash.sm3_256(plaindata.getBytes());
  6. // 构造执行 TAPP 请求,调用 TAPP 接口 "TestHash"
  7. testReqMethod = "TestHash";
  8. tappExecuteRequest = TappExecuteRequest.builder()
  9. .defaultRequest(tappId, tappVersion, testReqMethod)
  10. .addBytes(plaindata.getBytes())
  11. .build();
  12. // 发送 TAPP 执行请求
  13. tappExecuteResponse = client.executeTapp(tappExecuteRequest);
  14. // 解析 TAPP 执行结果
  15. Assert.assertTrue(tappExecuteResponse.isRequestSuccess());
  16. Assert.assertTrue(tappExecuteResponse.isExecuteSuccess());
  17. System.out.println("plaindata: " + Hex.toHexString(plaindata.getBytes()));
  18. System.out.println("expectedSha256hash: " + Hex.toHexString(expectedSha256hash));
  19. System.out.println("sha256Hash: " + tappExecuteResponse.getReturnValue().toUtf8StringList().get(0));
  20. System.out.println("expectedSm3hash: " + Hex.toHexString(expectedSm3hash));
  21. System.out.println("sm3256hash: " + tappExecuteResponse.getReturnValue().toUtf8StringList().get(1));
  22. // 测试HMAC算法
  23. plaindata = "this is a test for hmac";
  24. String secret = "12345678";
  25. // 本地计算HmacSha256和HmacSha1
  26. byte[] expectedHmacSha256 = Hash.hmac_sha256(plaindata.getBytes(), secret.getBytes());
  27. byte[] expectedHmacSha1 = Hash.hmac_sha1(plaindata.getBytes(), secret.getBytes());
  28. // 构造执行 TAPP 请求,调用 TAPP 接口 "TestHMAC"
  29. testReqMethod = "TestHMAC";
  30. tappExecuteRequest = TappExecuteRequest.builder()
  31. .defaultRequest(tappId, tappVersion, testReqMethod)
  32. .addBytes(plaindata.getBytes())
  33. .addBytes(secret.getBytes())
  34. .build();
  35. // 发送 TAPP 执行请求
  36. tappExecuteResponse = client.executeTapp(tappExecuteRequest);
  37. // 解析 TAPP 执行结果
  38. Assert.assertTrue(tappExecuteResponse.isRequestSuccess());
  39. Assert.assertTrue(tappExecuteResponse.isExecuteSuccess());
  40. System.out.println("Hmacsha256 : " + tappExecuteResponse.getReturnValue().toUtf8StringList().get(0));
  41. System.out.println("expectedHmacsha256: " + Hex.toHexString(expectedHmacSha256));
  42. System.out.println("Hmacsha1 : " + tappExecuteResponse.getReturnValue().toUtf8StringList().get(1));
  43. System.out.println("expectedHmacsha1: " + Hex.toHexString(expectedHmacSha1));

RSA 签名和验签

TAPP 内部可以使用该函数进行 RSA 签名和验签。

  • TAPP 接口示例
  1. INTERFACE std::string TestRsaSign(std::string prikey, std::string digest_name, std::string data) {
  2. std::string signature;
  3. int res_code = RsaSign(prikey, digest_name, data, signature);
  4. if(res_code != 1){
  5. print("Failed to sign data by RSA: %d", res_code);
  6. }
  7. return signature;
  8. }
  9. INTERFACE int TestRsaVerify(std::string pubkey, std::string digest_name, std::string data, std::string signature) {
  10. return RsaVerify(pubkey, digest_name, data, signature);
  11. }
  • SDK 使用示例
  1. // 测试RSA签名和验签
  2. String plainData = "this is test for rsaSign & rsaVerify";
  3. UserKeyPair userKeyPair = UserKeyFactory.generateKeyPair(KeyTypeEnum.RSA_4096_KEY);
  4. byte[] sig = RSATool.RSASign(plainData.getBytes(), userKeyPair.getPrivateKey().getEncoded());
  5. Assert.assertTrue(RSATool.RSAVerify(plainData.getBytes(), sig, userKeyPair.getPublicKey().getEncoded()));
  6. String priKey = Base64.toBase64String(userKeyPair.getPrivateKey().getEncoded());
  7. String pubKey = Base64.toBase64String(userKeyPair.getPublicKey().getEncoded());
  8. String RSAPriKeyPEM = CryptoUtils.priKey2PemString(userKeyPair.getPrivateKey());
  9. //构造 TAPP 执行请求,测试 TAPP "TestRsaSign" 接口
  10. String testReqMethod = "TestRsaSign";
  11. TappExecuteRequest tappExecuteRequest = TappExecuteRequest.builder()
  12. .defaultRequest(tappId, tappVersion, testReqMethod)
  13. .addString(RSAPriKeyPEM)
  14. .addString("SHA256")
  15. .addString(plainData)
  16. .build();
  17. //发送 TAPP 执行请求
  18. TappExecuteResponse tappExecuteResponse = client.executeTapp(tappExecuteRequest);
  19. //解析 TAPP 执行响应
  20. Assert.assertTrue(tappExecuteResponse.isRequestSuccess());
  21. Assert.assertTrue(tappExecuteResponse.isExecuteSuccess());
  22. String signature = tappExecuteResponse.getReturnValue().toUtf8String();
  23. System.out.println("signature: " + signature);
  24. Assert.assertEquals(Base64.toBase64String(sig), signature);
  25. //构造 TAPP 执行请求,测试 TAPP "TestRsaVerify" 接口
  26. testReqMethod = "TestRsaVerify";
  27. tappExecuteRequest = TappExecuteRequest.builder()
  28. .defaultRequest(tappId, tappVersion, testReqMethod)
  29. .addString(pubKey)
  30. .addString("SHA256")
  31. .addString(plainData)
  32. .addString(Base64.toBase64String(sig))
  33. .build();
  34. //发送 TAPP 执行请求
  35. tappExecuteResponse = client.executeTapp(tappExecuteRequest);
  36. //解析 TAPP 执行响应
  37. Assert.assertTrue(tappExecuteResponse.isRequestSuccess());
  38. Assert.assertTrue(tappExecuteResponse.isExecuteSuccess());
  39. Assert.assertEquals(1, tappExecuteResponse.getReturnValue().toInt32());

TAPP ECDSA 签名

  • TAPP 接口示例
  1. INTERFACE std::vector<std::string> TestTappEcdsaSign(std::string data) {
  2. std::vector<std::string> ret;
  3. std::string signature;
  4. int err_code = 1;
  5. err_code = TappEcdsaSign(data, signature, KEY_ALGO_TYPE::ECDSA_RAW_SECP256K1_KEY);
  6. if(err_code != 1){
  7. ret.push_back(std::to_string(err_code));
  8. return ret;
  9. }
  10. std::string base64_sig;
  11. err_code = Base64Encode(signature, base64_sig);
  12. if(err_code != 1){
  13. ret.push_back(std::to_string(err_code));
  14. return ret;
  15. }
  16. ret.push_back(std::to_string(err_code));
  17. ret.push_back(base64_sig);
  18. return ret;
  19. }
  • SDK 使用示例
  1. //构造 TAPP 执行请求,测试 TAPP "TestTappEcdsaSign" 接口
  2. String plainData = "this is test for TappECDSASign";
  3. testReqMethod = "TestTappEcdsaSign";
  4. tappExecuteRequest = TappExecuteRequest.builder()
  5. .defaultRequest(tappId, tappVersion, testReqMethod)
  6. .addString(plainData)
  7. .build();
  8. //发送 TAPP 执行请求
  9. tappExecuteResponse = client.executeTapp(tappExecuteRequest);
  10. //解析 TAPP 执行响应
  11. Assert.assertTrue(tappExecuteResponse.isRequestSuccess());
  12. Assert.assertTrue(tappExecuteResponse.isExecuteSuccess());
  13. String errorCode = tappExecuteResponse.getReturnValue().toUtf8StringList().get(0);
  14. Assert.assertTrue(errorCode.equals("1"));
  15. String ecdsaSignature = tappExecuteResponse.getReturnValue().toUtf8StringList().get(1);
  16. byte[] tappSignPK = tappInfo.getVerificationKeys().get(KeyTypeEnum.ECDSA_RAW_SECP256K1_KEY);
  17. System.out.println("signature: " + Hex.toHexString(Base64.decode(ecdsaSignature)));
  18. System.out.println("verify ret: "+ ECDSATool.ECDSAVerify(plainData.getBytes(), tappSignPK, Base64.decode(ecdsaSignature)));

Envelope 信封加密解密

TAPP 内部可以使用该函数进行基于 ECIES-SECP256K1 算法的加密解密。支持多方用户数据加密后,由第三方服务平台融合多方加密数据并请求执行 TAPP,服务平台无法获取用户隐私数据。

c3s.003

  • TAPP 接口示例
  1. INTERFACE std::string TestEnvelopeOpen(const std::string& enc_data) {
  2. std::string plain_data;
  3. int res_code = EnvelopeOpen(enc_data, plain_data);
  4. if(res_code != 1){
  5. print("Failed to open envelope: %d", res_code);
  6. plain_data = "Failed";
  7. }
  8. return plain_data;
  9. }
  10. INTERFACE std::string TestEnvelopeBuild(const std::string& plain_data, const std::string& pk) {
  11. std::string ret_envelope;
  12. int res_code = EnvelopeBuild(pk, plain_data, ret_envelope);
  13. if(res_code != 1){
  14. print("Failed to open envelope: %d", res_code);
  15. ret_envelope = "Failed";
  16. }
  17. return ret_envelope;
  18. }
  • SDK 使用示例
  1. // 获取 TAPP 信息
  2. TappInfo tappInfo = client.getTappInfo(tappId, tappVersion);
  3. // 本地重新生成新的 EC 公私钥对,构造密文信封
  4. String plainData = "this is test for envelopeOpen & envelopeBuild";
  5. UserKeyPair eciesKey = UserKeyFactory.generateKeyPair(KeyTypeEnum.ECIES_SECP256K1_KEY);
  6. byte[] tappEnvelope = EnvelopeUtils.buildTappEnvelope(tappInfo.getEncryptionKeys().get(KeyTypeEnum.ECIES_SECP256K1_KEY), eciesKey.getPrivateKey().getEncoded(), plainData.getBytes());
  7. // 构造 TAPP 执行请求, 测试 TAPP 'TestEnvelopeOpen' 接口
  8. String testReqMethod = "TestEnvelopeOpen";
  9. TappExecuteRequest tappExecuteRequest = TappExecuteRequest.builder()
  10. .defaultRequest(tappId, tappVersion, testReqMethod)
  11. .addBytes(tappEnvelope)
  12. .build();
  13. // 发送 TAPP 执行请求,合约内执行 tapp 信封解密
  14. TappExecuteResponse tappExecuteResponse = client.executeTapp(tappExecuteRequest);
  15. Assert.assertTrue(tappExecuteResponse.isRequestSuccess());
  16. Assert.assertTrue(tappExecuteResponse.isExecuteSuccess());
  17. // 校验本地明文是否与合约内解密的明文相等
  18. Assert.assertEquals(plainData, tappExecuteResponse.getReturnValue().toUtf8String());
  19. // 构造密文信封
  20. tappEnvelope = EnvelopeUtils.buildTappEnvelope(tappInfo, eciesKey, plainData.getBytes()).tlvEncode();
  21. // 构造 TAPP 执行请求, 测试 TAPP 'TestEnvelopeOpen' 接口
  22. tappExecuteRequest = TappExecuteRequest.builder()
  23. .defaultRequest(tappId, tappVersion, testReqMethod)
  24. .addBytes(tappEnvelope)
  25. .build();
  26. // 发送 TAPP 执行请求,合约内执行 tapp 信封解密
  27. tappExecuteResponse = client.executeTapp(tappExecuteRequest);
  28. Assert.assertTrue(tappExecuteResponse.isRequestSuccess());
  29. Assert.assertTrue(tappExecuteResponse.isExecuteSuccess());
  30. Assert.assertEquals(plainData, tappExecuteResponse.getReturnValue().toUtf8String());
  31. // 使用本地SDK生成的隐私秘钥构造密文信封
  32. tappEnvelope = client.getKeyStore().buildTappEnvelope(tappInfo, plainData.getBytes());
  33. // 构造 TAPP 执行请求, 测试 TAPP 'TestEnvelopeOpen' 接口
  34. tappExecuteRequest = TappExecuteRequest.builder()
  35. .defaultRequest(tappId, tappVersion, testReqMethod)
  36. .addBytes(tappEnvelope)
  37. .build();
  38. // 发送 TAPP 执行请求
  39. tappExecuteResponse = client.executeTapp(tappExecuteRequest);
  40. Assert.assertTrue(tappExecuteResponse.isRequestSuccess());
  41. Assert.assertTrue(tappExecuteResponse.isExecuteSuccess());
  42. Assert.assertEquals(plainData, tappExecuteResponse.getReturnValue().toUtf8String());
  43. // 构造 TAPP 执行请求, 测试 TAPP 'TestEnvelopeBuild' 接口
  44. testReqMethod = "TestEnvelopeBuild";
  45. tappExecuteRequest = TappExecuteRequest.builder()
  46. .defaultRequest(tappId, tappVersion, testReqMethod)
  47. .addBytes(plainData.getBytes())
  48. .addBytes(eciesKey.getPublicKey().getEncoded())
  49. .build();
  50. // 发送 TAPP 执行请求
  51. tappExecuteResponse = client.executeTapp(tappExecuteRequest);
  52. // 解析 TAPP 执行结果
  53. Assert.assertTrue(tappExecuteResponse.isRequestSuccess());
  54. Assert.assertTrue(tappExecuteResponse.isExecuteSuccess());
  55. byte[] tappExecutedEnvelope = tappExecuteResponse.getReturnValue().toBytes();
  56. byte[] envelopeRecoverPlainData = EnvelopeUtils.openTappEnvelope(tappInfo.getEncryptionKeys().get(KeyTypeEnum.ECIES_SECP256K1_KEY), eciesKey.getPrivateKey().getEncoded(), tappExecutedEnvelope);
  57. Assert.assertTrue(Arrays.equals(plainData.getBytes(), envelopeRecoverPlainData));
  58. // 构造 TAPP 执行请求, 测试 TAPP 'TestEnvelopeBuild' 接口
  59. tappExecuteRequest = TappExecuteRequest.builder()
  60. .defaultRequest(tappId, tappVersion, testReqMethod)
  61. .addBytes(plainData.getBytes())
  62. .addBytes(client.getKeyStore().getSecretKeypair().getPublicKey().getEncoded())
  63. .build();
  64. // 发送 TAPP 执行请求
  65. tappExecuteResponse = client.executeTapp(tappExecuteRequest);
  66. // 解析 TAPP 执行结果
  67. Assert.assertTrue(tappExecuteResponse.isRequestSuccess());
  68. Assert.assertTrue(tappExecuteResponse.isExecuteSuccess());
  69. tappExecutedEnvelope = tappExecuteResponse.getReturnValue().toBytes();
  70. envelopeRecoverPlainData = client.getKeyStore().openTappEnvelope(tappInfo, tappExecutedEnvelope);
  71. Assert.assertTrue(Arrays.equals(plainData.getBytes(), envelopeRecoverPlainData));

ECElgamalEnvelope 信封解密

TAPP 内部可以使用该函数进行基于 ECElgamal-SECP256K1 算法的解密。支持数据一方加密后多方解密。

c3s.004

  • TAPP 接口示例
  1. INTERFACE std::string TestEcElgamalEnvelopeOpen(std::string prikey, std::string cipher_data) {
  2. uint32_t curve_type = 0;
  3. std::string plain_data;
  4. int res_code = ECElgamalEnvelopeOpen(curve_type, prikey, cipher_data, plain_data);
  5. if(res_code != 1){
  6. print("Failed to open envelope: %d", res_code);
  7. plain_data = "Failed";
  8. }
  9. return plain_data;
  10. }
  11. INTERFACE uint32_t TestEcElgamalEnvelopeBatchOpen(std::string enc_prikey, std::vector<std::string> cipher_data_batch) {
  12. uint32_t curve_type = 0;
  13. uint32_t success_count = 0;
  14. std::string plain_data;
  15. std::string plain_prikey;
  16. int res_code = EnvelopeOpen(enc_prikey, plain_prikey);
  17. if(res_code != 1){
  18. print("Failed to open prikey envelope: %d", res_code);
  19. return 0;
  20. }
  21. for(auto cipher_data: cipher_data_batch) {
  22. if(cipher_data==""){
  23. continue;
  24. }
  25. int res_code = ECElgamalEnvelopeOpen(curve_type, plain_prikey, Hex2Bin(cipher_data), plain_data);
  26. if(res_code != 1){
  27. print("Failed to ecelgamal open envelope: %d", res_code);
  28. success_count++;
  29. }
  30. }
  31. return success_count;
  32. }
  • SDK 使用示例
  1. // 本地构造公私钥对、明文 plainBytes
  2. byte[] plainBytes = "this is test for ecElgamalEnvelopeOpen".getBytes();
  3. int pkSize = 3;
  4. String[] publicKeys = new String[pkSize];
  5. UserKeyPair user1Keypair = UserKeyFactory.generateKeyPair(KeyTypeEnum.ECELGAMAL_SECP256K1_KEY);
  6. UserKeyPair user2Keypair = UserKeyFactory.generateKeyPair(KeyTypeEnum.ECELGAMAL_SECP256K1_KEY);
  7. UserKeyPair user3Keypair = UserKeyFactory.generateKeyPair(KeyTypeEnum.ECELGAMAL_SECP256K1_KEY);
  8. publicKeys[0] = Base64.toBase64String(user1Keypair.getRawPublicKey());
  9. publicKeys[1] = Base64.toBase64String(user2Keypair.getRawPublicKey());
  10. publicKeys[2] = Base64.toBase64String(user3Keypair.getRawPublicKey());
  11. // 本地对明文数据进行 ECElgamalEncrypt 加密
  12. byte[] ciphertext = ECElgamalTool.ECElgamalEncrypt(CryptoSuiteTypeEnum.SECP256K1, publicKeys, plainBytes);
  13. System.out.println("ciphertext: " + Hex.toHexString(ciphertext));
  14. byte[] plaintext = ECElgamalTool.ECElgamalDecrypt(CryptoSuiteTypeEnum.SECP256K1, user3Keypair.getRawPrivateKey(), ciphertext);
  15. System.out.println("recovered plaintext:" + Hex.toHexString(plaintext));
  16. // 构造执行 TAPP 请求
  17. String testReqMethod = "TestEcElgamalEnvelopeOpen";
  18. tappExecuteRequest = TappExecuteRequest.builder()
  19. .defaultRequest(tappId, tappVersion, testReqMethod)
  20. .addBytes(user3Keypair.getRawPrivateKey())
  21. .addBytes(ciphertext)
  22. .build();
  23. // 发送执行 TAPP 请求
  24. TappExecuteResponse tappExecuteResponse = client.executeTapp(tappExecuteRequest);
  25. // 解析 TAPP 执行结果
  26. Assert.assertTrue(tappExecuteResponse.isRequestSuccess());
  27. Assert.assertTrue(tappExecuteResponse.isExecuteSuccess());
  28. assertEquals(plainBytes, tappExecuteResponse.getReturnValue().toBytes());

TAPP LOG

Tapp 中可以通过 API LOG_DEBUG 等打印信息,调用者可以查看日志信息。SDK 中相关的操作包括:安装时指定Tapp 打印的日志级别,执行 tapp 后查看其中的 tapp。TAPP LOG每行长度限制512,超长会截断。

  1. String testReqMethod = "TestLog";
  2. byte[] bytecodes = FileUtils.readFileToByteArray(new File(TEST_CONTRACT_FILE));
  3. // 安装 tapp,设置日志级别为INFO
  4. // 那么在 tapp 执行过程中,低于 INFO 级别的LOG(如 LOG_DEBUG)将不会生效
  5. TappInstallRequest tappInstallRequest = TappInstallRequest.builder()
  6. .newTapp(tappId, tappVersion, bytecodes)
  7. .setTappLogLevel(TappLogLevelEnum.TAPP_LOG_INFO)
  8. .upgradeable()
  9. .build();
  10. TappInstallResponse tappInstallResponse = client.installTapp(tappInstallRequest);
  11. System.out.println(tappInstallResponse);
  12. Assert.assertTrue(tappInstallResponse.isSuccess());
  13. // 检验 tappInfo 中包含设置的 log level: info
  14. TappInfo tappInfo = client.getTappInfo(tappId, tappVersion);
  15. Assert.assertNotNull(tappInfo);
  16. Assert.assertEquals(tappInfo.getTappProperty().getTappLogLevel(), TappLogLevelEnum.TAPP_LOG_INFO);
  17. // 再次执行,会得到 info level 级别的 log
  18. TappExecuteRequest tappExecuteRequest = TappExecuteRequest.builder()
  19. .defaultRequest(tappId, tappVersion, testReqMethod)
  20. .build();
  21. TappExecuteResponse tappExecuteResponse = client.executeTapp(tappExecuteRequest);
  22. Assert.assertTrue(tappExecuteResponse.isExecuteSuccess());
  23. String logs = tappExecuteResponse.getTappLog();