Sm3Util源自sm-crypto,sm-crypto没有暴露gethash方法,将所有源码拿过来自己暴露,smjs为整个sm-crypto声明文件(.d.ts)
import * as asn1Cms from "@peculiar/asn1-cms";
import * as asn1X509 from "@peculiar/asn1-x509";
import * as asn1Schema from "@peculiar/asn1-schema";
import { Convert } from "pvtsutils";
import {sm2} from '../smjs';
import {Hex} from 'arraybuffer-encoding'
import {AsnConvert} from "@peculiar/asn1-schema";
import Sm3Util from "../utils/sm3-util";
import {Attributes} from "../asn/asn-attributes";
const {Encode, Decode} = Hex;
class Pkcs7SignSm2 {
private static SM3_DEF_UID: string = '1234567812345678';
/**
* p7签名
* @param cert b64编码证书
* @param privateKey 16进制字符私钥(暂定)
* @param originData 原文字符串
*/
static sign(cert: string, privateKey: string, originData: string): string{
// 解析base64证书信息
const certHex = Convert.FromBase64(cert);
const certificate = asn1Schema.AsnConvert.parse(certHex, asn1X509.Certificate);
// 公钥信息
const publicKey = Encode(certificate.tbsCertificate.subjectPublicKeyInfo.subjectPublicKey);
// 原文16进制字符串
const originDataHex = new Buffer(originData).toString('hex');
// 带公钥参数sm3 hash值
const digest = Sm3Util.getHash(originDataHex, publicKey);
// 待签名数据 摘要数据需要加type value 0420
const attributes: Attributes = new Attributes([new asn1Cms.Attribute({
attrType: '1.2.840.113549.1.9.4',
attrValues: [Decode('0420' + digest)]
})]);
// 签名数据转16进制,修改源码不在sm-crypto内部转(可能存在问题)
const attributeStr = Encode(AsnConvert.serialize(attributes));
// 签名 der:true补全sm2签名r,s(tlv)
const signData = sm2.doSignature(attributeStr, privateKey, {
der: true,
hash: true,
publicKey: publicKey,
userId: this.SM3_DEF_UID
});
const signedData = new asn1Cms.SignedData();
// 构造数字信封
signedData.encapContentInfo = new asn1Cms.EncapsulatedContentInfo({
eContentType: '1.2.840.113549.1.7.1',
eContent: new asn1Cms.EncapsulatedContent({
single: new asn1Schema.OctetString(Decode(originDataHex))
})
});
signedData.digestAlgorithms = new asn1Cms.DigestAlgorithmIdentifiers([
new asn1Cms.DigestAlgorithmIdentifier({
algorithm: '1.2.156.10197.1.401'
})
]);
signedData.signerInfos = new asn1Cms.SignerInfos([new asn1Cms.SignerInfo({
version: 1,
sid: new asn1Cms.SignerIdentifier({
issuerAndSerialNumber: new asn1Cms.IssuerAndSerialNumber({
issuer: certificate.tbsCertificate.issuer,
serialNumber: certificate.tbsCertificate.serialNumber
}),
}),
digestAlgorithm: new asn1Cms.DigestAlgorithmIdentifier({
algorithm: '1.2.156.10197.1.401'
}),
signatureAlgorithm: new asn1Cms.SignatureAlgorithmIdentifier({
algorithm: '1.2.156.10197.1.501'
}),
signature: new asn1Schema.OctetString(Decode(signData)),
signedAttrs: attributes
})]);
const cms = new asn1Cms.ContentInfo({
contentType: asn1Cms.id_signedData,
content: asn1Schema.AsnConvert.serialize(signedData),
});
const raw = asn1Schema.AsnConvert.serialize(cms);
return Convert.ToBase64(raw);
}
/**
* p7验签
* @param cert b64编码证书
* @param signature b64编码签名数据
*/
static verify(cert: string, signature: string): boolean {
// 解析base64证书信息
const certHex = Convert.FromBase64(cert);
const certificate = asn1Schema.AsnConvert.parse(certHex, asn1X509.Certificate);
// 公钥信息
const publicKey = Encode(certificate.tbsCertificate.subjectPublicKeyInfo.subjectPublicKey);
// 签名数据转arrayBuffer
const arrayBuffer = Convert.FromBase64(signature);
// 解析contentInfo
const contentInfo = asn1Schema.AsnConvert.parse(arrayBuffer, asn1Cms.ContentInfo);
// 解析signedData
const signedData = asn1Schema.AsnConvert.parse(contentInfo.content, asn1Cms.SignedData);
const eContent: any = signedData.encapContentInfo.eContent;
// 原文ArrayBuffer
const data = eContent.single.buffer;
// 原文16进制字符
const originDataHex = Encode(data);
// 原文摘要计算
const digest = Sm3Util.getHash(originDataHex, publicKey);
// Attributes数据
const attributes: Attributes = new Attributes(signedData.signerInfos[0].signedAttrs);
// 将Attributes数据转换为自定义ASN结构
const signedAttrs = AsnConvert.parse(AsnConvert.serialize(attributes), Attributes);
const attrValues = signedAttrs[0].attrValues[0];
// 摘要数据去掉tl 0420 与原文摘要对比
const signDataDigest = Encode(attrValues).substr(4, 128);
if (digest !== signDataDigest) {
console.log("error");
return false;
}
const signInfo = signedData.signerInfos[0].signature;
// 签名数据
const sign = Encode(signInfo.buffer);
// 待签名数据
const attributeStr = Encode(AsnConvert.serialize(signedAttrs));
console.log("attributeStr2 " + attributeStr);
return sm2.doVerifySignature(attributeStr, sign, publicKey,{
der: true,
hash: true,
publicKey: publicKey,
userId: this.SM3_DEF_UID
});
}
}
export default Pkcs7SignSm2;