HarmonyOS 鸿蒙Next SM2加解密demo请求:按照api文档sm2无法完成解密
HarmonyOS 鸿蒙Next SM2加解密demo请求:按照api文档sm2无法完成解密
按照api文档sm2无法完成解密,麻烦提供sm2加解密demo
鸿蒙支持将密文转为 c1c2c3 以及c1c3c2 但是鸿蒙段进行解密目前仅支持 c1c3c2 需要将c1c2c3的格式在java端进行转换为c1c3c2
import { cryptoFramework } from '[@kit](/user/kit).CryptoArchitectureKit';
import { buffer, util } from '[@kit](/user/kit).ArkTS';
import { BusinessError } from '[@kit](/user/kit).BasicServicesKit';
[@Entry](/user/Entry)
[@Component](/user/Component)
struct sm2Api12Crypto {
[@State](/user/State) message: string = '点击开始';
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
.onClick(() => {
main()
})
}
.width('100%')
}
.height('100%')
}
}
// 加密消息
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;
}
//根据密钥参数生成sm2公钥
export async function convertStrToPubKey(keyStr: string): Promise<cryptoFramework.PubKey> {
const pubKeyStr = keyStr.startsWith('04') ? keyStr.slice(2) : keyStr
const pkPart1 = pubKeyStr.slice(0, pubKeyStr.length / 2)
const pkPart2 = pubKeyStr.slice(pubKeyStr.length / 2)
const pk: cryptoFramework.Point = {
x: BigInt('0x' + pkPart1),
y: BigInt('0x' + pkPart2),
}
const pubKeySpec: cryptoFramework.ECCPubKeySpec = {
params: cryptoFramework.ECCKeyUtil.genECCCommonParamsSpec('NID_sm2'),
pk: pk,
algName: 'SM2',
specType: cryptoFramework.AsyKeySpecType.PUBLIC_KEY_SPEC
}
const keypairGenerator = cryptoFramework.createAsyKeyGeneratorBySpec(pubKeySpec)
return await keypairGenerator.generatePubKey()
}
//根据密钥参数生成sm2私钥
export async function convertStrToPriKey(keyStr: string): Promise<cryptoFramework.PriKey> {
const sk = BigInt('0x' + keyStr)
const priKeySpec: cryptoFramework.ECCPriKeySpec = {
params: cryptoFramework.ECCKeyUtil.genECCCommonParamsSpec('NID_sm2'),
sk: sk,
algName: 'SM2',
specType: cryptoFramework.AsyKeySpecType.PRIVATE_KEY_SPEC
}
const keypairGenerator = cryptoFramework.createAsyKeyGeneratorBySpec(priKeySpec)
return await keypairGenerator.generatePriKey()
}
// SM2 main代码
async function main() {
let base64 = new util.Base64Helper();
//十六进制的公私钥
// let pubKeyStr = "0453402B95F3584F36B9A7129A6B5C6109F2DBC7C94BE7858DB66C48AF38CB5C3B76883EE4BF18E270607191E233EAC0A95ECFB8EF6FE80C5F782DE24F018DEB5F"
let pubKeyStr = "BDeRJMU7GFuy+9v3VIe34rf3P/mu3ZpJqLzzjIczCyoZ+yiybnWp8KbD8fMOPTt6+jJyGpTraVYtPUw1joURwVs="
// let priKeyStr = "5B9270E0ADF86A101167610FCCD375A6549DC14E9225951EF3A4640F26D6CD9C"
let priKeyStr = "JlkWOVILswt9+dRUmAnJjd2C70aLwStFm2KZhEDL2kg="
// 公钥base64转十六进制
let u8aPub = base64.decodeSync(pubKeyStr)
console.error('Uint8Array u8aP result string:' + u8aPub);
let bufPub = buffer.from(u8aPub);
console.error('hex u8aPub result string:' + bufPub.toString('hex'));
let hexPub = "04379124c53b185bb2fbdbf75487b7e2b7f73ff9aedd9a49a8bcf38c87330b2a19fb28b26e75a9f0a6c3f1f30e3d3b7afa32721a94eb69562d3d4c358e8511c15b"
// 私钥base64转十六进制
let u8aPri = base64.decodeSync(priKeyStr)
console.error('Uint8Array u8aP result string:' + u8aPri);
let bufPri = buffer.from(u8aPri);
console.error('hex u8aPri result string:' + bufPri.toString('hex'));
let hexPri = "26591639520bb30b7df9d4549809c98ddd82ef468bc12b459b62998440cbda48"
//安卓加密后的密文
/*try {
let spec : cryptoFramework.SM2CipherTextSpec = {
xCoordinate: BigInt('20625015362595980457695435345498579729138244358573902431560627260141789922999'),
yCoordinate: BigInt('48563164792857017065725892921053777369510340820930241057309844352421738767712'),
cipherTextData: new Uint8Array([100,227,78,195,249,179,43,70,242,69,169,10,65,123]),
hashData: new Uint8Array([87,167,167,247,88,146,203,234,83,126,117,129,52,142,82,54,152,226,201,111,143,115,169,125,128,42,157,31,114,198,109,244]),
}
let data = cryptoFramework.SM2CryptoUtil.genCipherTextBySpec(spec, 'C1C3C2');
console.info('genCipherTextBySpec success');
} catch (err) {
let e: BusinessError = err as BusinessError;
console.error(`genCipherTextBySpec error, ${e.code}, ${e.message}`);
}*/
/*try {
let cipherTextArray = new Uint8Array([48,118,2,32,45,153,88,82,104,221,226,43,174,21,122,248,5,232,105,41,92,95,102,224,216,149,85,236,110,6,64,188,149,70,70,183,2,32,107,93,198,247,119,18,40,110,90,156,193,158,205,113,170,128,146,109,75,17,181,109,110,91,149,5,110,233,209,78,229,96,4,32,87,167,167,247,88,146,203,234,83,126,117,129,52,142,82,54,152,226,201,111,143,115,169,125,128,42,157,31,114,198,109,244,4,14,100,227,78,195,249,179,43,70,242,69,169,10,65,123]);
let cipherText : cryptoFramework.DataBlob = {data : cipherTextArray};
let spec : cryptoFramework.SM2CipherTextSpec = cryptoFramework.SM2CryptoUtil.getCipherTextSpec(cipherText, 'C1C3C2');
// console.error('getCipherTextSpec success'+ spec);
} catch (err) {
let e: BusinessError = err as BusinessError;
console.error(`getCipherTextSpec error, ${e.code}, ${e.message}`);
}*/
//根据密钥参数生成对应的公私钥
let pubKey = await convertStrToPubKey(hexPub)
console.error("pubKey=======>" + pubKey.getEncoded().data)
let priKey = await convertStrToPriKey(hexPri)
console.error("priKey=======>" + priKey.getEncoded().data)
// 此处为明文
// 把字符串按utf-8解码为Uint8Array
let message = "aaaa"
let plainText: cryptoFramework.DataBlob = { data: new Uint8Array(buffer.from(message, 'utf-8').buffer) };
let encryptText = await encryptMessagePromise(pubKey, plainText);
console.error("encryptText=======>" + encryptText.data.toString())
console.error("encryptHex=======>" + buffer.from(encryptText.data).toString('hex'))
//reslut 是加密后的密文数据
let spec: cryptoFramework.SM2CipherTextSpec = cryptoFramework.SM2CryptoUtil.getCipherTextSpec(encryptText, 'C1C3C2');
/*
* C1 = spec.xCoordinate.toString(16) + spec.yCoordinate.toString(16)
* C2 = buffer.from(spec.cipherTextData).toString('hex')
* C3 = buffer.from(spec.hashData).toString('hex')
* */
console.error(""+spec.xCoordinate.toString(16).length)
let encryptHex = spec.xCoordinate.toString(16) + spec.yCoordinate.toString(16) + buffer.from(spec.cipherTextData).toString('hex') + buffer.from(spec.hashData).toString('hex')
console.error("C1C2C3解码后16进制数据=======>" + encryptHex)
let encryptBase64 = base64.encodeToStringSync(new Uint8Array(buffer.from(encryptHex, 'hex').buffer))
console.error("C1C2C3解码后数据Base64Str=======>" + encryptBase64)
//将加密的密文数据解码转换为安卓可用数据(用于鸿蒙和安卓的交接)
// let b = new SM2_Ciphertext().d2i_SM2_Ciphertext(buffer.from(str).toString('hex'))
// console.log("解码后数据=======>" + b)
/* //解密得到结果
let res = await decryptMessagePromise(priKey, encryptText)
console.log("a=======>" + buffer.from(res.data).toString('utf-8'))*/
//针对安卓的密文处理,转成鸿蒙可用uint8Array数组数据
let c = new Uint8Array(buffer.from(new SM2_Ciphertext().i2d_SM2_Ciphertext(encryptHex), 'hex').buffer)
console.error("java转asn1=======>" + c)
//对安卓生成的的密文进行解密
try {
let resa = await decryptMessagePromise(priKey, { data: c }/*encryptText*/)
console.log("安卓的密文解码数据=======>" + buffer.from(resa.data).toString('utf-8'))
}catch (error){
console.error(JSON.stringify(error));
}
}
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";
}
class SM2_Ciphertext {
/**
* 用于将SM2裸密文数据序列化
* [@param](/user/param) primal_data SM2裸密钥数据,长度为96+明文长度(字节),输入格式为C1C3C2的Hex字符串
* [@returns](/user/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_message: string = C1x_title + sm2_sequence.C1x + C1y_title + sm2_sequence.C1y + C2_title + sm2_sequence.C2 + C3_title + sm2_sequence.C3;
let sequence_lenHex:string = this.genLenHex(sequence_message);
let standard_data = "30" + sequence_lenHex + sequence_message;
return standard_data;
}
/**
* 用于将标准SM2密文数据解码
* [@param](/user/param) standard_data 标准SM2密文数据,符合ASN.1编码标准,输入格式为Hex字符串
* [@returns](/user/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);
// message = this.readC3(sm2_sequence, message);
// console.log(sm2_sequence.toString());
let primal_data: string = sm2_sequence.C1x + sm2_sequence.C1y + sm2_sequence.C3 + sm2_sequence.C2;
// let primal_data: string = sm2_sequence.C1x + sm2_sequence.C1y + sm2_sequence.C2 + sm2_sequence.C3;
return primal_data;
}
// 生成传入内容的长度域
genLenHex(content: string): string {
let size: number = content.length / 2;
let lenHex: string ;
if (size.toString(16).length % 2 == 1 ) {
lenHex= '0' + size.toString(16);
}else {
lenHex = size.toString(16);
}
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() {
console.error("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;
}
/** 转鸿蒙签名后的数据
**/
d2i_SM2_SignText(standard_data: string): string {
let randNum:string = "";
let signText:string = "";
let message = standard_data.slice("30".length, standard_data.length);
let sequence_lenHex: string = this.getLenHex(message);
message = message.slice(sequence_lenHex.length, message.length);
try {
let randNum_len: string = message.slice(0, 4);
if(randNum_len == "0220"){
randNum = message.slice(4, 4+64);
message = message.slice(4+64, message.length);
} else {
//randNum_len == "022100"
randNum = message.slice(6, 6+64);
message = message.slice(6+64, message.length);
}
let signText_len: string = message.slice(0, 4);
if(signText_len == "0220"){
signText = message.slice(4, 4+64);
} else {
//randNum_len == "022100"
signText = message.slice(6, 6+64);
}
} catch (e) {
console.error("d2i_SM2_SignText", "SignText format is err");
}
return randNum+signText
}
}
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);
}
}
更多关于HarmonyOS 鸿蒙Next SM2加解密demo请求:按照api文档sm2无法完成解密的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
针对您提出的HarmonyOS鸿蒙Next SM2加解密demo请求,若按照API文档SM2无法完成解密,可能是以下几个原因导致的:
-
密钥对不匹配:确保加密使用的公钥与解密使用的私钥是一对匹配的密钥。
-
填充方式不一致:加密和解密过程中使用的填充方式必须一致,如PKCS#1、OAEP等。
-
参数设置错误:检查API调用时传入的参数,如随机数生成器、哈希函数等,确保它们符合SM2算法的要求。
-
数据格式问题:加密后的数据格式和解密时接收的数据格式必须一致,包括字节序、编码方式等。
-
API版本问题:确认您使用的HarmonyOS SDK版本是否支持您正在使用的SM2 API,以及是否存在已知的bug或限制。
-
编码转换:在数据传输或存储过程中,确保加密数据的编码和解码方式一致,避免数据损坏。
如果以上检查均无误,但问题依旧存在,可能是由于API实现或系统环境的特定问题。此时,您可以尝试联系官网客服获取进一步的技术支持。官网地址是:https://www.itying.com/category-93-b0.html ,以便获得更专业的帮助。