使用自定义公私钥执行SM2算法加解密操作

使用自定义公私钥执行SM2算法加解密操作

HarmonyOS
2024-05-28 21:24:58
浏览
收藏 0
回答 1
待解决
回答 1
按赞同
/
按时间
ssscan

使用的 OS 能力及相关的核心 API

- cryptoFramework.createAsyKeyGeneratorBySpec

- generator.convertKey

核心代码解释

import cryptoFramework from '@ohos.security.cryptoFramework'; 
import util from '@ohos.util'; 
import { BusinessError } from '@ohos.base'; 
 
@Entry 
@Component 
struct Index { 
  private plain: string = 'Hello World'; 
  @State message: string = this.plain; 
  @State encrypted: string = ''; 
 
  // 字符串转字节流数组 
  stringToUint8Array(str: string) { 
    let arr = new Uint8Array(str.length); 
    for (let i = 0, j = str.length; i < j; ++i) { 
      arr[i] = str.charCodeAt(i); 
    } 
    return new Uint8Array(arr); 
  } 
 
  // 字节流转成可理解的字符串 
  uint8ArrayToString(array: Uint8Array) { 
    // 将UTF-8编码转换成Unicode编码 
    let out: string = ""; 
    let index: number = 0; 
    let len: number = array.length; 
    while (index < len) { 
      let character = array[index++]; 
      switch (character >> 4) { 
        case 0: 
        case 1: 
        case 2: 
        case 3: 
        case 4: 
        case 5: 
        case 6: 
        case 7: 
          out += String.fromCharCode(character); 
          break; 
        case 12: 
        case 13: 
          out += String.fromCharCode(((character & 0x1F) << 6) | (array[index++] & 0x3F)); 
          break; 
        case 14: 
          out += String.fromCharCode(((character & 0x0F) << 12) | ((array[index++] & 0x3F) << 6) | ((array[index++] & 0x3F) << 0)); 
          break; 
        default: 
          break; 
      } 
    } 
    return out; 
  } 
 
  // 字节流转成16进制表示的字符串 
  uint8ArrayToHexStr(data: Uint8Array): string { 
    let hexString = ''; 
    let i: number; 
    for (i = 0; i < data.length; i++) { 
      let char = ('00' + data[i].toString(16)).slice(-2); 
      hexString += char; 
    } 
    return hexString; 
  } 
 
  // 16进制表示的字符串转成字节流 
  hexStr2Uint8Array(str: string): Uint8Array { 
    let arr = new Uint8Array(str.length / 2); 
    let index = 0; 
    for (let i = 0; i < str.length; i += 2) { 
      let tmp: string = str.slice(i, i + 2); 
      let result = Number.parseInt("0x" + tmp); 
      arr[index++] = result 
    } 
    return arr; 
  } 
 
  base64Encode(data: Uint8Array): string { 
    let base64 = new util.Base64Helper(); 
    return base64.encodeToStringSync(data); 
  } 
 
  base64Decode(data: string): Uint8Array { 
    let base64 = new util.Base64Helper(); 
    return base64.decodeSync(data); 
  } 
 
  // 生成 公钥/私钥/密钥对 的 params 属性方法 
  genSM2CommonSpec(): cryptoFramework.ECCCommonParamsSpec { 
    let fieldFp: cryptoFramework.ECFieldFp = { 
      fieldType: "Fp", 
      p: BigInt("0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF") 
    } 
 
    let G: cryptoFramework.Point = { 
      x: BigInt("0x32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7"), 
      y: BigInt("0xBC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0") 
    } 
 
    let SM2CommonSpec: cryptoFramework.ECCCommonParamsSpec = { 
      algName: "ECC", 
      specType: cryptoFramework.AsyKeySpecType.COMMON_PARAMS_SPEC, 
      field: fieldFp, 
      a: BigInt("0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC"), 
      b: BigInt("0x28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93"), 
      g: G, 
      n: BigInt("0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123"), 
      h: 1 
    } 
 
    return SM2CommonSpec; 
  } 
 
  // 异步获取密钥对象 
  async getPriKek(): Promise<cryptoFramework.PriKey | null> { 
    // 密钥字符串:6d562d653d74f41bff9c3f2359e5add416a931c44783b9afdf5c3327121c2266 
    let sk: bigint = BigInt("0x6d562d653d74f41bff9c3f2359e5add416a931c44783b9afdf5c3327121c2266"); 
 
    // 私钥对象数据 
    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; 
  } 
 
  async getPubKek(): Promise<cryptoFramework.PubKey | null> { 
    // 公钥:8dc347c86a9c5f75c38c64ed68cd240298e19512f863ab9fa7b3f3768f4730ef7e08c2374172937f64f81ae9b1ac51d069309da960c14568f964875ed4c2396f 
    // 共 128 位,前 64 为为 x 值;后 64 位为 y 值 
    //转16进制放入对应的位置 
    let pk: cryptoFramework.Point = { 
      x: BigInt("0x8dc347c86a9c5f75c38c64ed68cd240298e19512f863ab9fa7b3f3768f4730ef"), 
      y: BigInt("0x7e08c2374172937f64f81ae9b1ac51d069309da960c14568f964875ed4c2396f") 
    } 
    // 私钥对象数据 
    let pubKey: cryptoFramework.ECCPubKeySpec = { 
      params: this.genSM2CommonSpec(), // 通用参数 
      pk: pk, // 公钥 
      algName: "ECC", // 指定算法 
      specType: cryptoFramework.AsyKeySpecType.PUBLIC_KEY_SPEC // 指定算法参数类型 
    } 
    let KeyPair: cryptoFramework.PubKey | null = null; 
    try { 
      let KeyPairGenerator: cryptoFramework.AsyKeyGeneratorBySpec; 
      KeyPairGenerator = cryptoFramework.createAsyKeyGeneratorBySpec(pubKey); 
      KeyPair = await KeyPairGenerator.generatePubKey() 
        .then((pubKey) => { 
          return pubKey; // 公钥获取成功 
        }) 
        .catch((e: Error): null => { 
          console.log(JSON.stringify(e)) 
          AlertDialog.show({ message: "PubKey get failed" }); 
          return null; 
        }) 
    } catch (err) { 
      let e: BusinessError = err as BusinessError; 
      console.error(`sync error, ${e.code}, ${e.message}`); 
      AlertDialog.show({ message: "PubKey get failed" }); 
      return null; 
    } 
    return KeyPair; 
  } 
 
  async convertPriKey(keyPair: cryptoFramework.PriKey, message: string) { 
    let priKey = keyPair; 
    let priKeyArr: Uint8Array = priKey.getEncoded().data; 
    console.log("PriKey code : " + this.uint8ArrayToHexStr(priKeyArr)); 
    console.log("PriKey data : " + this.base64Encode(priKeyArr)); 
    let priKeyBlob: cryptoFramework.DataBlob = { data: priKeyArr }; 
    let decoder = cryptoFramework.createCipher("SM2_256|SM3"); 
    let generator = cryptoFramework.createAsyKeyGenerator("SM2_256"); 
    let keypair: cryptoFramework.KeyPair; 
    try { 
      generator.convertKey(null, priKeyBlob) 
        .then((keyPair) => { // 解密前,使用私钥初始化 
          keypair = keyPair; 
          return decoder.init(cryptoFramework.CryptoMode.DECRYPT_MODE, keypair.priKey, null); 
        }) 
        .then(() => { // 对密文进行对应的处理后,执行解密操作 
          console.info("SM2 DecryptOutPut message is " + this.hexStr2Uint8Array(message)) 
          let input: cryptoFramework.DataBlob = { data: this.hexStr2Uint8Array(message) }; 
          return decoder.doFinal(input); 
        }) 
        .then((dataBlob: cryptoFramework.DataBlob) => { // 获取明文 
          console.info("SM2 DecryptOutPut base64Encode is " + this.base64Encode(dataBlob.data)); 
          console.info("SM2 DecryptOutPut uint8ArrayToHexStr is " + this.uint8ArrayToHexStr(dataBlob.data)); 
          console.info("SM2 DecryptOutPut result uint8ArrayToString is " + this.uint8ArrayToString(dataBlob.data)); 
          this.message = this.uint8ArrayToString(dataBlob.data); // 解密完成 
        }) 
        .catch((e: BusinessError) => { // 解密失败 
          console.log("doFinal result: code = " + e.code + ", message = " + e.message); 
          AlertDialog.show({ message: "Decrypt failed" }); 
        }); 
    } catch (err) { 
      let e: BusinessError = err as BusinessError; 
      console.error(`sync error, ${e.code}, ${e.message}`); 
      AlertDialog.show({ message: "Decrypt failed" }); 
    } 
  } 
 
  async convertPubKey(keyPair: cryptoFramework.PubKey, plain: string) { 
    let pubKey = keyPair; 
    let pubKeyArr: Uint8Array = pubKey.getEncoded().data; 
    console.log("PubKey code : " + this.uint8ArrayToHexStr(pubKeyArr)); 
    console.log("PubKey data : " + this.base64Encode(pubKeyArr)); 
    let pubKeyBlob: cryptoFramework.DataBlob = { data: pubKeyArr }; 
    let cipher = cryptoFramework.createCipher("SM2_256|SM3"); 
    let generator = cryptoFramework.createAsyKeyGenerator("SM2_256"); 
    let keypair: cryptoFramework.KeyPair; 
    try { 
      generator.convertKey(pubKeyBlob, null) 
        .then((keyPair) => { // 获取公钥并初始化 cipher 对象 
          keypair = keyPair; 
          return cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, keypair.pubKey, null); 
        }) 
        .then(() => { // 根据明文执行加密操作 
          let input: cryptoFramework.DataBlob = { data: this.stringToUint8Array(plain) }; 
          return cipher.doFinal(input); 
        }) 
        .then((dataBlob: cryptoFramework.DataBlob) => { // 获取密文 
          console.info("SM2 EncryptOutPut param is " + dataBlob.data); 
          console.info("SM2 EncryptOutPut base64Encode is " + this.base64Encode(dataBlob.data)); 
          console.info("SM2 EncryptOutPut uint8ArrayToHexStr is " + this.uint8ArrayToHexStr(dataBlob.data)); 
          console.info("SM2 EncryptOutPut result uint8ArrayToString is " + this.uint8ArrayToString(dataBlob.data)); 
          this.encrypted = this.uint8ArrayToHexStr(dataBlob.data); // 加密成功 
        }) 
        .catch((e: BusinessError) => { // 加密失败 
          console.log("doFinal result: code = " + e.code + ", message = " + e.message); 
          AlertDialog.show({ message: "Encrypt failed" }); 
        }); 
    } catch (err) { 
      let e: BusinessError = err as BusinessError; 
      console.error(`sync error, ${e.code}, ${e.message}`); 
      AlertDialog.show({ message: "Encrypt failed" }); 
    } 
  } 
 
  build() { 
    Column() { 
      Row() { 
        Text("明文:") 
          .fontSize(20) 
          .width("20%") 
          .fontWeight(FontWeight.Bold) 
 
        TextInput({ placeholder: this.message, text: this.message }) 
          .fontSize(20) 
          .fontWeight(FontWeight.Bold) 
          .width("65%") 
          .onChange((value: string) => { 
            this.message = value; 
          }) 
      } 
      .padding({ 
        top: "20pv", 
        bottom: "10pv" 
      }) 
      .justifyContent(FlexAlign.Start) 
 
      Row() { 
        Text("密文:") 
          .fontSize(20) 
          .width("20%") 
          .fontWeight(FontWeight.Bold) 
 
        TextArea({ placeholder: this.encrypted, text: this.encrypted }) 
          .fontSize(20) 
          .fontWeight(FontWeight.Bold) 
          .width("65%") 
          .onChange((value: string) => { 
            this.encrypted = value; 
          }) 
      } 
      .padding({ 
        top: "20pv", 
        bottom: "10pv" 
      }) 
      .justifyContent(FlexAlign.Start) 
 
      Button("Sm2DecryptPromise") 
        .width(120) 
        .height(30) 
        .margin({ 
          top: "20pv", 
          bottom: "10pv" 
        }) 
        .onClick(() => { 
          this.getPriKek().then((keyPair: cryptoFramework.PriKey) => { 
            this.convertPriKey(keyPair, this.encrypted); 
          }) 
        }) 
 
      Button("Sm2EncryptPromise") 
        .width(120) 
        .height(30) 
        .margin({ 
          top: "10pv", 
          bottom: "10pv" 
        }) 
        .onClick(() => { 
          this.getPubKek().then((keyPair: cryptoFramework.PubKey) => { 
            this.convertPubKey(keyPair, this.message); 
          }); 
        }) 
 
      Button("Reset") 
        .width(120) 
        .height(30) 
        .margin({ 
          top: "10pv", 
          bottom: "10pv" 
        }) 
        .onClick(() => { 
          this.message = this.plain; 
          this.encrypted = ""; 
        }) 
    } 
    .width('100%') 
  } 
}
分享
微博
QQ
微信
回复
2024-05-29 22:32:53
相关问题
如何使用国密SM2算法进行加解密
859浏览 • 1回复 待解决
加解密算法库框架使用
452浏览 • 1回复 待解决
如何使用SM4的CBC模式加解密
174浏览 • 1回复 待解决
基于加解密算法框架的规格问题
194浏览 • 1回复 待解决
SM4采用OFB模式进行加解密
310浏览 • 1回复 待解决
SM4 CBC模式加解密,有好的方案吗?
448浏览 • 1回复 待解决
Payment Kit的签名公私钥怎么获取?
428浏览 • 1回复 待解决
【求助】自定义相机Camera2焦距异常
6545浏览 • 1回复 待解决
自定义弹窗自定义转场动画
382浏览 • 1回复 待解决
自定义弹窗使用相关问题
357浏览 • 1回复 待解决
自定义弹窗如何嵌套使用
428浏览 • 1回复 待解决
如何使用和加载自定义字体
674浏览 • 1回复 待解决
自定义装饰器的使用问题
209浏览 • 0回复 待解决