HarmonyOS开发中 SM2密钥对转换失败?

sm2私钥:3c9xxxxbe7f24c2xxxx223466804xxxxxxad284def02eb
SM2密钥转换失败报错,通过await generator1.convertKey(null, priKeyBlob);
发现通过await generator.generateKeyPair();生成的私钥是51字节,我们的私钥是32字节,这个转换有问题,请问怎么处理,是否和SM2 userid签名有关
ConvertEcPriKey: d2i_ECPrivateKey fail
09-23 19:17:52.784 10787-10838 C02f10/[HCF] com.bwton.szfreego E HcfPrintOpensslError: [Openssl]: engine fail, error code = 109052072, error string = error:068000A8:asn1 encoding routines::wrong tag
09-23 19:17:52.784 10787-10838 C02f10/[HCF] com.bwton.szfreego E ConvertKeyAsyncWorkProcess: convert key fail.

阅读 660
avatarAI BotBETA

在HarmonyOS开发中遇到SM2密钥对转换失败的问题,通常与密钥的格式、长度或编码方式不匹配有关。从您提供的信息来看,有几个关键点需要注意:

  1. 私钥长度问题

    • SM2算法中,私钥通常是一个大整数(通常是256位,即32字节),但在某些实现中,私钥可能还包含其他信息(如公钥参数、UserID等),这可能导致私钥数据看起来更长。
    • 您提到的51字节的私钥可能是包含了额外信息的格式(如PKCS#8或类似格式),而您手中的32字节私钥则是纯粹的私钥数据。
  2. 转换函数问题

    • await generator1.convertKey(null, priKeyBlob); 这行代码尝试将私钥priKeyBlob转换,但null可能不是该函数的预期参数。通常,您需要指定密钥的源格式和目标格式。
    • 如果convertKey函数期望的是特定格式的私钥(如PKCS#8或PEM),那么直接使用32字节的原始私钥数据可能会导致失败。
  3. 错误分析

    • 错误代码error:068000A8:asn1 encoding routines::wrong tag 指出ASN.1编码时遇到了错误的标签,这通常与数据格式不匹配有关。

解决方案

  1. 检查并修改密钥格式

    • 如果您只有32字节的私钥,确保convertKey函数能够处理这种格式的私钥。如果该函数要求特定的格式(如PKCS#8),您需要使用相应的库(如OpenSSL)来将私钥包装成该格式。
    • 示例(使用OpenSSL将原始私钥转换为PKCS#8格式):

      openssl ec -in raw_private_key.pem -out pkcs8_private_key.pem -outform PEM -conv_form_der -param_enc explicit

      注意:raw_private_key.pem 应包含您的32字节私钥,但可能需要先以适当的方式编码(如十六进制)。

  2. 修改convertKey函数的调用

    • 查看convertKey函数的文档,了解如何正确指定源格式和目标格式。
    • 如果函数不支持直接处理原始私钥,您可能需要先将其转换为支持的格式。
  3. 调试和日志

    • 增加日志输出,以查看在转换过程中convertKey函数接收到的实际数据。
    • 确保在调用convertKey之前,私钥数据没有被意外修改或损坏。
  4. 查阅文档和社区

    • 查看HarmonyOS和OpenSSL的官方文档,了解关于SM2密钥管理的更多信息。
    • 搜索类似的错误报告和解决方案,特别是在HarmonyOS和SM2相关的开发者社区和论坛中。
  5. 考虑使用第三方库

    • 如果内置的密钥管理功能不满足您的需求,可以考虑使用第三方库来处理SM2密钥的生成、转换和签名验证。
1 个回答

当调用convertKey方法将外来二进制数据转换为算法库非对称密钥对象时,公钥应满足ASN.1语法、X.509规范、DER编码格式,私钥应满足ASN.1语法、PKCS#8规范、DER编码格式。 convertKey方法中,公钥和密钥二进制数据非必选项,可单独传入公钥或私钥的数据,生成对应只包含公钥或私钥的KeyPair对象。
请参考:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides...
当前系统版本的指定生成密钥的API为convertKey,其中SM2密钥生成的参数只支持封装并ASN.1序列化后的数据(公钥91字节,私钥51字节),请参考下列demo获取相应的私钥:

// 生成 公钥/私钥/密钥对 的 params 属性方法 
genSM2CommonSpec(): cryptoFramework.ECCCommonParamsSpec { 
  let fieldFp: cryptoFramework.ECFieldFp = { 
    fieldType: "Fp", 
    p: BigInt("0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF") 
  } 
 
  let G: cryptoFramework.Point = { 
    x: BigInt("0x32C4AE2C1F19811xxxxC9948FE30BBFF2660BE1715A4589334C74C7"), 
    y: BigInt("0xBC3736A2F4F6779Cxxxx692153D0A9877CC62A474002DF32E52139F0A0") 
  } 
 
  let SM2CommonSpec: cryptoFramework.ECCCommonParamsSpec = { 
    algName: "ECC", 
    specType: cryptoFramework.AsyKeySpecType.COMMON_PARAMS_SPEC, 
    field: fieldFp, 
    a: BigInt("0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC"), 
    b: BigInt("0x28E9FA9E9D9F5E3xxxx9789F515AB8F92DDBCBD414D940E93"), 
    g: G, 
    n: BigInt("0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B2xx53BBF40939D54123"), 
    h: 1 
  } 
 
  return SM2CommonSpec; 
} 
 
// 异步获取密钥对象 
async getPriKek(): Promise<cryptoFramework.PriKey | null> { 
  // 密钥字符串:6d562d653d74f41bff9c3f2359xxxxxxxxx416a931c44783b9afdf5c3327121c2266 
  let sk: bigint = BigInt("0x6d562d653d74f4xxxxxc3f2359e5add416a931c44783b9afdf5c3327121c2266"); 
 
  // 私钥对象数据 
  let priKey: cryptoFramework.ECCPriKeySpec = { 
    params: this.genSM2CommonSpec(), // 通用参数 
    sk: sk, // 密钥 
    algName: "ECC", // 指定算法 
    specType: cryptoFramework.AsyKeySpecType.PRIVATE_KEY_SPEC // 指定算法参数类型 
  } 
 
  let KeyPair: cryptoFramework.PriKey | null = null; 
  try { 
  let KeyPairGenerator: cryptoFramework.AsyKeyGeneratorBySpec; 
  KeyPairGenerator = cryptoFramework.createAsyKeyGeneratorBySpec(priKey); 
  KeyPair = await KeyPairGenerator.generatePriKey() 
    .then((keyPair) => { 
      return keyPair; // 私钥获取成功 
    }) 
    .catch((e: Error): null => { 
      console.log(JSON.stringify(e)) 
      AlertDialog.show({message:"PriKey get failed"}); 
      return null; 
    }) 
} catch (err) { 
  let e: BusinessError = err as BusinessError; 
  console.error(`sync error, ${e.code}, ${e.message}`); 
  AlertDialog.show({message:"PriKey get failed"}); 
  return null; 
} 
return KeyPair; 
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题