SM2示例中的加解密方式如何使用Java端生成的公私钥

Java端使用SM2生成了一对公私钥,使用该公私钥在HarmonyOS的SM2加解密方法中会提示失败。下面是方法:

const pubK = 
  "0473227b0b71e097b47c4d461a315a402f352157027a8955fdb71ede6190b6b8d86fe935423e41ba9706710516558960d1f27785151814d4210d35cef9316948f1" 
const priK = "b627f6fc21519812f97560cc60c7f0af28cccb61275a4af966eec08b26f718f1" 
let textEncoder = new util.TextEncoder(); 
let info = textEncoder.encodeInto(pubK); 
let info2 = textEncoder.encodeInto(priK); 
 
// 先对密钥进行base64解码,获取密钥Uint8Array对象 
let base64 = new util.Base64Helper(); 
let pkDataDatabase64 = base64.decodeSync(info); 
let skDataDatabase64 = base64.decodeSync(info2); 
this.genKeyPairByData(pkDataDatabase64, skDataDatabase64); 
 
async genKeyPairByData(pubKeyData: Uint8Array, priKeyData: Uint8Array) { 
  let pubKeyBlob: cryptoFramework.DataBlob = { data: pubKeyData }; 
  let priKeyBlob: cryptoFramework.DataBlob = { data: priKeyData }; 
  let sm2Generator = cryptoFramework.createAsyKeyGenerator('SM2_256'); 
  sm2Generator.convertKey(pubKeyBlob, priKeyBlob).then((result) => { 
    console.log('生成成功:') 
    return result; 
  }).catch((error: BusinessError) => { 
    console.log(JSON.stringify((error))); 
    return null; 
  }) 
}

怎么才能直接使用Java端的公私钥来进行SM2加解密。

HarmonyOS
5天前
浏览
收藏 0
回答 1
待解决
回答 1
按赞同
/
按时间
Heiang

参考:

// 加密消息 
async function encryptMessagePromise(publicKey: cryptoFramework.PubKey, plainText: cryptoFramework.DataBlob) { 
  //密钥类型为SM2_256、摘要算法为SM3的Cipher 
  let cipher = cryptoFramework.createCipher('SM2_256|SM3'); 
  await cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, publicKey, null); 
  let encryptData = await cipher.doFinal(plainText); 
  return encryptData; 
} 
 
// 解密消息 
async function decryptMessagePromise(privateKey: cryptoFramework.PriKey, cipherText: cryptoFramework.DataBlob) { 
  let decoder = cryptoFramework.createCipher('SM2_256|SM3'); 
  await decoder.init(cryptoFramework.CryptoMode.DECRYPT_MODE, privateKey, null); 
  let decryptData = await decoder.doFinal(cipherText); 
  return decryptData; 
} 
 
export async function convertStrToPriKey(keyStr: string): Promise<cryptoFramework.PriKey> { 
  let sk = BigInt("0x" + keyStr) 
  let priKeySpec: cryptoFramework.ECCPriKeySpec = { 
    params: cryptoFramework.ECCKeyUtil.genECCCommonParamsSpec('NID_sm2'), 
    sk: sk, 
    algName: "SM2", 
    specType: cryptoFramework.AsyKeySpecType.PRIVATE_KEY_SPEC 
  } 
  let keypairGenerator = cryptoFramework.createAsyKeyGeneratorBySpec(priKeySpec) 
  return await keypairGenerator.generatePriKey() 
} 
 
export async function convertStrToPubKey(keyStr: string): Promise<cryptoFramework.PubKey> { 
  let pubKeyStr = keyStr.startsWith("04") ? keyStr.slice(2) : keyStr 
  let pkPart1 = pubKeyStr.slice(0, pubKeyStr.length / 2) 
  let pkPart2 = pubKeyStr.slice(pubKeyStr.length / 2) 
  let pk: cryptoFramework.Point = { 
    x: BigInt("0x" + pkPart1), 
    y: BigInt("0x" + pkPart2), 
  } 
  let pubKeySpec: cryptoFramework.ECCPubKeySpec = { 
    params: cryptoFramework.ECCKeyUtil.genECCCommonParamsSpec('NID_sm2'), 
    pk: pk, 
    algName: "SM2", 
    specType: cryptoFramework.AsyKeySpecType.PUBLIC_KEY_SPEC 
  } 
  let keypairGenerator = cryptoFramework.createAsyKeyGeneratorBySpec(pubKeySpec) 
  return await keypairGenerator.generatePubKey() 
} 
 
// SM2 main代码 
async function main() { 
  //十六进制的公私钥 
  let pubKeyStr = "0453402B95F3584F36B9A7129A6B5C6109F2DBC7C94BE7858DB66C48AF38CB5C3B76883EE4BF18E270607191E233EAC0A95ECFB8EF6FE80C5F782DE24F018DEB5F" 
  let priKeyStr = "5B9270E0ADF86A101167610FCCD375A6549DC14E9225951EF3A4640F26D6CD9C" 
  //安卓加密后的密文 
  let a = "53ce193ad865c6d97742da78b18a21d0ca66200fe080284d774d5500915be2425cea2f310c9a423bc2d08ce5c1e78a75cfd66d88688a0e2076a45614307e4372aa10b514841cfe7bff08fc82d96bdf35754696571e5fbedd552d1ab7c54bff796a0e3fd72902"; 
 
  //根据密钥参数生成对应的公私钥 
  let pubKey = await convertStrToPubKey(pubKeyStr) 
  let priKey = await convertStrToPriKey(priKeyStr) 
  // 此处为明文 
  let message = 'This is a test'; 
  // 把字符串按utf-8解码为Uint8Array 
  let plainText: cryptoFramework.DataBlob = { data: new Uint8Array(buffer.from(message, 'utf-8').buffer) }; 
  let encryptText = await encryptMessagePromise(pubKey, plainText); 
  console.log("encryptText=======>" + buffer.from(encryptText.data).toString('hex')) 
  //将加密的密文数据解码转换为安卓可用数据(用于HarmonyOS和安卓的交接) 
  let b = new SM2_Ciphertext().d2i_SM2_Ciphertext(buffer.from(encryptText.data).toString('hex')) 
  console.log("解码后数据=======>" + b) 
 
  //解密得到结果 
  let res = await decryptMessagePromise(priKey, encryptText) 
  console.log("a=======>" + buffer.from(res.data).toString('utf-8')) 
 
  //针对安卓的密文处理,转成HarmonyOS可用uint8Array数组数据 
  let c = new Uint8Array(buffer.from(new SM2_Ciphertext().i2d_SM2_Ciphertext(a), 'hex').buffer) 
  //对安卓生成的的密文进行解密 
  let resa = await decryptMessagePromise(priKey, { data: c }) 
  console.log("安卓的密文解码数据=======>" + buffer.from(resa.data).toString('utf-8')) 
}

sm2Ciphertext.ets

import hilog from '@ohos.hilog'; 
import { SM2_SEQUENCE } from './sm2Sequence'; 
 
export class ASN1Util { 
  static BOOLEAN: string = "01"; 
  static INTEGER: string = "02"; 
  static BIT_STRING: string = "03"; 
  static OCTET_STRING: string = "04"; 
  static NULL: string = "05"; 
  static REAL: string = "09"; 
  static ENUMERATED: string = "0a"; 
  static SEQUENCE: string = "30"; 
  static SET: string = "31"; 
} 
 
export class SM2_Ciphertext { 
  /** 
   * 用于将SM2裸密文数据序列化 
   * @param primal_data SM2裸密钥数据,长度为96+明文长度(字节),输入格式为C1C3C2的Hex字符串 
   * @returns 返回序列化后的标准密文数据,输出格式为Hex字符串 
   */ 
  i2d_SM2_Ciphertext(primal_data: string): string { 
    let sm2_sequence = new SM2_SEQUENCE(); 
    sm2_sequence.C1x = primal_data.slice(0, 64); 
    primal_data = primal_data.slice(64, primal_data.length); 
    sm2_sequence.C1y = primal_data.slice(0, 64); 
    primal_data = primal_data.slice(64, primal_data.length); 
    sm2_sequence.C3 = primal_data.slice(0, 64); 
    primal_data = primal_data.slice(64, primal_data.length); 
    sm2_sequence.C2 = primal_data; 
 
    let C1x_title: string = (Number.parseInt("0x" + sm2_sequence.C1x.slice(0, 2)) > 127) ? "022100" : "0220"; 
    let C1y_title: string = (Number.parseInt("0x" + sm2_sequence.C1y.slice(0, 2)) > 127) ? "022100" : "0220"; 
    let C3_title: string = "0420"; 
    let C2_title: string = "04" + this.genLenHex(sm2_sequence.C2); 
    let sequence_message: string = C1x_title + sm2_sequence.C1x + C1y_title + sm2_sequence.C1y + C3_title + sm2_sequence.C3 + C2_title + sm2_sequence.C2; 
    let sequence_lenHex:string = this.genLenHex(sequence_message); 
 
    let standard_data = "30" + sequence_lenHex + sequence_message; 
    return standard_data; 
  } 
 
  /** 
   * 用于将标准SM2密文数据解码 
   * @param standard_data 标准SM2密文数据,符合ASN.1编码标准,输入格式为Hex字符串 
   * @returns 返回ASN.1解码后的SM2密文数据 
   */ 
  d2i_SM2_Ciphertext(standard_data: string): string { 
    let message: string = standard_data; 
    // 起始标识为03 
    if (!message.startsWith(ASN1Util.SEQUENCE)) { 
      this.ciphertextErr(); 
    } 
    message = message.slice(ASN1Util.SEQUENCE.length, message.length); 
 
    // SM2 sequence 内容的长度 
    let sequence_lenHex: string = this.getLenHex(message); 
    message = message.slice(sequence_lenHex.length, message.length); 
    let sequence_len: number = this.lenHex2number(sequence_lenHex); 
    if (sequence_len != message.length / 2) { 
      this.ciphertextErr(); 
    } 
 
    let sm2_sequence = new SM2_SEQUENCE(); 
    message = this.readC1(sm2_sequence, message); 
    message = this.readC3(sm2_sequence, message); 
    message = this.readC2(sm2_sequence, message); 
    let primal_data: string = sm2_sequence.C1x + sm2_sequence.C1y + sm2_sequence.C3 + sm2_sequence.C2; 
    return primal_data; 
  } 
 
  // 生成传入内容的长度域 
  genLenHex(content: string): string { 
    let size: number = content.length / 2; 
    let lenHex: string = ("00" + size.toString(16)).slice(-2); 
    if (size < 0x80) { 
      return lenHex; 
    } 
    let lenHex_size: number = lenHex.length / 2; 
    return (lenHex_size | 0x80).toString(16) + lenHex; 
  } 
 
  // 提取长度域的Hex字符串 
  getLenHex(data: string): string { 
    let byte: number = Number.parseInt("0x" + data.slice(0, 2)); 
    let len_size: number = byte > 127 ? byte - 0x80 + 1 : 1; 
    return data.slice(0, len_size * 2); 
  } 
 
  // 将长度域的Hex字符串转为整型 
  lenHex2number(lenHex: string): number { 
    if (lenHex.length == 2) { 
      return Number.parseInt("0x" + lenHex); 
    } 
    return Number.parseInt("0x" + lenHex.slice(2, lenHex.length)); 
  } 
 
  ciphertextErr() { 
    hilog.error(0, "d2i_SM2_Ciphertext", "密文格式错误"); 
    throw new Error("SM2 ciphertext error!") 
  } 
 
  readC1(sm2_sequence: SM2_SEQUENCE, data: string): string { 
    let xy: string[] = []; 
    for (let i = 0; i < 2; i++) { 
      if (data.startsWith("0220")) { 
        xy[i] = data.slice(4, 68); 
        data = data.slice(68, data.length); 
      } else if (data.startsWith("022100")) { 
        xy[i] = data.slice(6, 70); 
        data = data.slice(70, data.length); 
      } else { 
        this.ciphertextErr(); 
      } 
    } 
    sm2_sequence.C1x = xy[0]; 
    sm2_sequence.C1y = xy[1]; 
    return data; 
  } 
 
  readC2(sm2_sequence: SM2_SEQUENCE, data: string): string { 
    if (data.startsWith(ASN1Util.OCTET_STRING)) { 
      data = data.slice(ASN1Util.OCTET_STRING.length, data.length); 
      let C2_lenHex = this.getLenHex(data); 
      data = data.slice(C2_lenHex.length, data.length) 
      if (this.lenHex2number(C2_lenHex) != data.length / 2) { 
        this.ciphertextErr() 
      } 
      sm2_sequence.C2 = data; 
    } else { 
      this.ciphertextErr(); 
    } 
    return data; 
  } 
 
  readC3(sm2_sequence: SM2_SEQUENCE, data: string): string { 
    if (data.startsWith("0420")) { 
      sm2_sequence.C3 = data.slice(4, 68); 
      data = data.slice(68, data.length); 
    } else { 
      this.ciphertextErr(); 
    } 
    return data; 
  } 
}

sm2Sequence.ets

export class SM2_SEQUENCE{ 
  private _C1x: string = ""; 
  private _C1y: string = ""; 
  private _C2: string = ""; 
  private _C3: string = ""; 
 
  public set C1x(value: string) { 
    this._C1x = value; 
  } 
 
  public get C1x(): string { 
    return this._C1x; 
  } 
 
  public set C1y(value: string) { 
    this._C1y = value; 
  } 
 
  public get C1y(): string { 
    return this._C1y; 
  } 
 
  public set C2(value: string) { 
    this._C2 = value; 
  } 
 
  public get C2(): string { 
    return this._C2; 
  } 
 
  public set C3(value: string) { 
    this._C3 = value; 
  } 
 
  public get C3(): string { 
    return this._C3; 
  } 
 
  public toString():string{ 
    return JSON.stringify(this); 
  } 
}
分享
微博
QQ
微信
回复
5天前
相关问题
如何使用国密SM2算法进行加解密
3242浏览 • 1回复 待解决
HarmonyOS Sm2和DES加解密问题
296浏览 • 1回复 待解决
HarmonyOS SM2SM4国密加解密使用demo
81浏览 • 1回复 待解决
如何使用SM4CBC模式加解密
748浏览 • 1回复 待解决
HarmonyOS SM2加签验签SM3摘要算法使用
246浏览 • 1回复 待解决
Payment Kit签名公私钥怎么获取?
1344浏览 • 1回复 待解决
huks sm2签名验签失败
63浏览 • 1回复 待解决
HarmonyOS SM2密钥对转换失败
403浏览 • 1回复 待解决
多种加密方式实现加解密
911浏览 • 1回复 待解决