@boxyhq/xml-crypto

中文文档
6.1.0发布于 2025/03/14MITCommonJS近 30 天下载 4526

Xml 节点.js 的数字签名和加密库

中文使用文档
文档目录23 节
  1. 安装
  2. 支持的算法
  3. 分类和转换算法
  4. 汉字算法
  5. 签名算法
  6. 签名 Xml 文档
  7. 正在验证 Xml 文档
  8. 关心隐性转变
  9. API 密码
  10. ưμ㼯a
  11. 签名Xml
  12. 自定义算法
  13. 同步签名和核查
  14. X.509 / 密钥格式
  15. 将 pfx 证书转换为 pem
  16. 实例
  17. 如何签名根节点( e) 马上就来了 (中文(简体) )
  18. 如何为签名添加前缀
  19. 如何指定签名的位置
  20. 更多实例( 马上就来了 (中文(简体) )
  21. 发展
  22. 更多信息
  23. 许可证

xml- cypto 数据

Build Gitpod Ready-to-Code

Xml 节点数字签名库. Xml加密即将到来. 写成纯洁的日记!

更多信息访问 我的博客 或者说 # 我的推特 # # my twitter #。 。 。 .

安装

安装方式 无数字 :

npm install xml-crypto

预设条件 打开 及其/bin在系统路径上。 我用了1.0.1c版本,但旧版本也应该有用.

支持的算法

分类和转换算法

汉字算法

签名算法

HMAC- SHA1 也可用, 但默认已禁用

以启用 HMAC-SHA1, 呼叫 enableHMAC() 以你为例 SignedXml。 。 。 .

这将启用HMAC并禁用数字签名算法. 由于密钥 使用基于HMAC的和公用的关键数字数据是很危险的 同时启用了签名算法 .

您可以使用自定义算法扩展 xml- crypto .

签名 Xml 文档

签名 xml 文档时, 您可以将以下选项传递到 SignedXml 自定义签名进程的构造器 :

  • privateKey - 说吧 [须 (单位:千美元) Buffer 或 pem 编码 String 包含您的私钥
  • publicCert - 说吧 [可选 (单位:千美元) Buffer 或 pem 编码 String 包含您的公钥
  • signatureAlgorithm - 说吧 [须 支持对象之一 签名算法。例如: sign.signatureAlgorithm = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
  • canonicalizationAlgorithm - 说吧 [须 支持对象之一 犬科化算法。例如: sign.canonicalizationAlgorithm = "http://www.w3.org/2001/10/xml-exc-c14n#WithComments"

使用此代码 :

var SignedXml = require("xml-crypto").SignedXml,
  fs = require("fs");

var xml = "<library>" + "<book>" + "<name>Harry Potter</name>" + "</book>" + "</library>";

var sig = new SignedXml({ privateKey: fs.readFileSync("client.pem") });
sig.addReference({
  xpath: "//*[local-name(.)='book']",
  digestAlgorithm: "http://www.w3.org/2000/09/xmldsig#sha1",
  transforms: ["http://www.w3.org/2001/10/xml-exc-c14n#"],
});
sig.canonicalizationAlgorithm = "http://www.w3.org/2001/10/xml-exc-c14n#";
sig.signatureAlgorithm = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
sig.computeSignature(xml);
fs.writeFileSync("signed.xml", sig.getSignedXml());

其结果是:

<library>
  <book Id="_0">
    <name>Harry Potter</name>
  </book>
  <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
    <SignedInfo>
      <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
      <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
      <Reference URI="#_0">
        <Transforms>
          <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
        </Transforms>
        <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
        <DigestValue>cdiS43aFDQMnb3X8yaIUej3+z9Q=</DigestValue>
      </Reference>
    </SignedInfo>
    <SignatureValue>vhWzpQyIYuncHUZV9W...[long base64 removed]...</SignatureValue>
  </Signature>
</library>

说明:

如果你设定 publicCert 编辑 getKeyInfoContent 属性, a <KeyInfo></KeyInfo> 带有公共证书的元素将在签名中生成:

<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
  <SignedInfo>
    ...[signature info removed]...
  </SignedInfo>
  <SignatureValue>vhWzpQyIYuncHUZV9W...[long base64 removed]...</SignatureValue>
  <KeyInfo>
    <X509Data>
      <X509Certificate>MIIGYjCCBJagACCBN...[long base64 removed]...</X509Certificate>
    </X509Data>
  </KeyInfo>
</Signature>

对于 getKeyInfoContent,默认执行 SignedXml.getKeyInfoContent 已提供.

要自定义此视图 自定义算法 举个例子.

正在验证 Xml 文档

当验证 xml 文档时, 您可以将以下选项传递到 SignedXml 用于自定义验证进程的构造器 :

  • publicCert - 说吧 [可选 您的证书为字符串、 PEM 格式的多个证书的字符串或缓冲
  • privateKey - 说吧 [可选 用于验证对称签名的私人密钥( HMAC)

用于检查签名的证书将首先通过调用 this.getCertFromKeyInfo(),哪个函数可以自定义。 如果这回 null,则 publicCert 已使用。 如果这是 null,则 privateKey 用于(对称签名应用程序).

示例

new SignedXml({
  publicCert: client_public_pem,
  getCertFromKeyInfo: () => null,
});

您可以在代码中使用任何您想要的多姆解析器( 或者没有, 取决于您的用法) 。 这个样本使用 缩写,所以你应该先安装它:

npm install @xmldom/xmldom

示例

var select = require("xml-crypto").xpath,
  dom = require("@xmldom/xmldom").DOMParser,
  SignedXml = require("xml-crypto").SignedXml,
  fs = require("fs");

var xml = fs.readFileSync("signed.xml").toString();
var doc = new dom().parseFromString(xml);

var signature = select(
  doc,
  "//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']",
)[0];
var sig = new SignedXml({ publicCert: fs.readFileSync("client_public.pem") });
sig.loadSignature(signature);
try {
  var res = sig.checkSignature(xml);
} catch (ex) {
  console.log(ex);
}

为了防止一些攻击 我们必须检查我们想要使用的内容 是已经签署的:

// Roll your own
const elem = xpath.select("/xpath_to_interesting_element", doc);
const uri = sig.getReferences()[0].uri; // might not be 0; it depends on the document
const id = uri[0] === "#" ? uri.substring(1) : uri;
if (
  elem.getAttribute("ID") != id &&
  elem.getAttribute("Id") != id &&
  elem.getAttribute("id") != id
) {
  throw new Error("The interesting element was not the one verified by the signature");
}

// Get the validated element directly from a reference
const elem = sig.references[0].getValidatedElement(); // might not be 0; it depends on the document
const matchingReference = xpath.select1("/xpath_to_interesting_element", elem);
if (!isDomNode.isNodeLike(matchingReference)) {
  throw new Error("The interesting element was not the one verified by the signature");
}

// Use the built-in method
const elem = xpath.select1("/xpath_to_interesting_element", doc);
try {
  const matchingReference = sig.validateElementAgainstReferences(elem, doc);
} catch {
  throw new Error("The interesting element was not the one verified by the signature");
}

// Use the built-in method with a an xpath expression
try {
  const matchingReference = sig.validateReferenceWithXPath("/xpath_to_interesting_element", doc);
} catch {
  throw new Error("The interesting element was not the one verified by the signature");
}

说明:

Xml- crypto api 需要您单独提供 xml 签名(" signature"... </ signature"),在 loadSignature 中)和所签名的 xml (在 检查Signature 中). 签名的 xml 可能包含也可能不包含签名, 但您仍然需要单独提供签名 .

关心隐性转变

如果无法校验签名的XML,那么一个可能的原因是存在一些隐藏的隐性变换(#).
(#)使待核查的XML文档正常化. 即去除标签内的额外空间,排序属性,导入在祖先节点声明的命名空间等.

这些暗中转变的原因可能来自: 复杂 xml 签名规格, (中文(简体) ), 它使 XML 开发者混淆,然后导致签名 XML 文档的不正确执行.

如果您一直无法进行验证, 值得猜测这样一个隐藏的变换, 并将其指定为以下选项 :

var options = {
  implicitTransforms: ["http://www.w3.org/TR/2001/REC-xml-c14n-20010315"],
  publicCert: fs.readFileSync("client_public.pem"),
};
var sig = new SignedXml(options);
sig.loadSignature(signature);
var res = sig.checkSignature(xml);

你可能觉得很难猜到这种变换,但有些典型的变换你可以尝试.

API 密码

ưμ㼯a

见 页:1 用于使用。 请注意,这实际上是在使用 另一个图书馆 作为执行的基础.

签名Xml

这个 SignedXml 构造器提供了签名和验证xml文档的抽象. 对象使用 new SignedXml(options?: SignedXmlOptions) 可能的选择是:

  • idMode - 默认 null - 如果值为: wssecurity 将会通过ws安全命名空间来创建/验证 id's.
  • idAttribute - 字符串 - 默认 Id 或者说 ID 或者说 id - 包含元素 id 的属性名称
  • privateKey - 字符串或缓冲 - 默认 null - 签字用的私人钥匙
  • publicCert - 字符串或缓冲 - 默认 null - 用于核查的公证书
  • signatureAlgorithm - 字符串 - 要使用的签名算法
  • canonicalizationAlgorithm - 字符串 - 默认 undefined - 拟使用的划线化算法
  • inclusiveNamespacesPrefixList - 字符串 - 默认 null - 名称空间前缀列表,以包含在犬科化期间
  • implicitTransforms - 字符串[] - 默认 [] - 核查期间使用的隐性变换清单
  • keyInfoAttributes - 对象 - 默认 {} - 属性和价值的散列 attrName: value 添加到密钥信息节点
  • getKeyInfoContent - 函数 - 默认 noop - 返回 KeyInfo 节点内容的函数
  • getCertFromKeyInfo - 函数 - 默认 SignedXml.getCertFromKeyInfo - 返回证书的函数 <KeyInfo /> 节点

API 密码

A 类 SignedXml 对象提供下列方法:

要签署 xml 文档 :

  • addReference(xpath, transforms, digestAlgorithm) - 增加一个xml元素:
    • xpath - 包含 XPath 表达式的字符串,其中引用了 xml 元素
    • transforms - 一组 转换算法,引用元素将按数组中的每个值转换
    • digestAlgorithm - 一个被支持的 散列算法
  • computeSignature(xml, [options]) - 计算给定的 xml 的签名:
    • xml - 包含 xml 文档的字符串
    • options - 具有下列特性的物体:
      • prefix - 作为生成的签名标记的前缀添加此值
      • attrs - 属性和价值的散列 attrName: value 添加到签名根节点
      • location - 定制签名位置,用 reference 键,该键应包含用于引用节点的 XPath 表达式, a action 键,其中应包含下列值之一: append, (中文(简体) ), prepend, (中文(简体) ), before, (中文(简体) ), after
      • existingPrefixes - 一系列前缀和命名空间 prefix: namespace 这不应该在签名中,因为它们已经存在于 xml
  • getSignedXml() - 返回带有签名的正本 xml 文档, 必须在 computeSignature
  • getSignatureXml() - 仅返回签名部分, 必须在 computeSignature
  • getOriginalXmlWithIds() - 返回在相关元素上添加的 Id 属性的正本 xml(需要验证), 必须在 computeSignature

要验证 xml 文档 :

  • loadSignature(signatureXml) - 将签名装入:
    • signatureXml - 字符串或节点对象(如 缩写 节点),包含签名的 xml 表示
  • checkSignature(xml) - 验证给定的 xml 文档并返回 true 如果验证成功

自定义算法

以下样本显示如何使用自定义算法来签名消息.

首先导入一些模块 :

var SignedXml = require("xml-crypto").SignedXml,
  fs = require("fs");

现在定义要执行的扩展点。 你可以选择一个或多个.

确定是否列入和内容 <KeyInfo /> 元素,函数 this.getKeyInfoContent() 名为. 缺省执行。 如果你想改变 此项执行,请提供您自己指定给财产的功能 this.getKeyInfoContent。如果您喜欢使用默认执行,请指定 SignedXml.getKeyInfoContent 改为 this.getKeyInfoContent 若为 没有属性和内容 <KeyInfo /> 元素,不会包含在 生成了 XML .

指定自定义属性 <KeyInfo />,将属性添加到 .keyInfoAttributes 属性.

自定义散列算法用于计算文摘. 如果您想要内置方法以外的散列, 请执行 .

function MyDigest() {
  this.getHash = function (xml) {
    return "the base64 hash representation of the given xml string";
  };

  this.getAlgorithmName = function () {
    return "http://myDigestAlgorithm";
  };
}

自定义签名算法 .

function MySignatureAlgorithm() {
  /*sign the given SignedInfo using the key. return base64 signature value*/
  this.getSignature = function (signedInfo, privateKey) {
    return "signature of signedInfo as base64...";
  };

  this.getAlgorithmName = function () {
    return "http://mySigningAlgorithm";
  };
}

自定义转换算法 .

function MyTransformation() {
  /*given a node (from the xmldom module) return its canonical representation (as string)*/
  this.process = function (node) {
    //you should apply your transformation before returning
    return node.toString();
  };

  this.getAlgorithmName = function () {
    return "http://myTransformation";
  };
}

自定义的cononicalization实际上与自定义转换相同. 它适用于签署的信息而不是参考文献.

function MyCanonicalization() {
  /*given a node (from the xmldom module) return its canonical representation (as string)*/
  this.process = function (node) {
    //you should apply your transformation before returning
    return "< x/>";
  };

  this.getAlgorithmName = function () {
    return "http://myCanonicalization";
  };
}

现在你需要注册新的算法:

/*register all the custom algorithms*/

signedXml.CanonicalizationAlgorithms["http://MyTransformation"] = MyTransformation;
signedXml.CanonicalizationAlgorithms["http://MyCanonicalization"] = MyCanonicalization;
signedXml.HashAlgorithms["http://myDigestAlgorithm"] = MyDigest;
signedXml.SignatureAlgorithms["http://mySigningAlgorithm"] = MySignatureAlgorithm;

现在做签名。 注意我们如何配置使用上述算法的签名 :

function signXml(xml, xpath, key, dest) {
  var options = {
    publicCert: fs.readFileSync("my_public_cert.pem", "latin1"),
    privateKey: fs.readFileSync(key),
    /*configure the signature object to use the custom algorithms*/
    signatureAlgorithm: "http://mySignatureAlgorithm",
    canonicalizationAlgorithm: "http://MyCanonicalization",
  };

  var sig = new SignedXml(options);

  sig.addReference({
    xpath: "//*[local-name(.)='x']",
    transforms: ["http://MyTransformation"],
    digestAlgorithm: "http://myDigestAlgorithm",
  });

  sig.addReference({
    xpath,
    transforms: ["http://MyTransformation"],
    digestAlgorithm: "http://myDigestAlgorithm",
  });
  sig.canonicalizationAlgorithm = "http://www.w3.org/2001/10/xml-exc-c14n#";
  sig.signatureAlgorithm = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
  sig.computeSignature(xml);
  fs.writeFileSync(dest, sig.getSignedXml());
}

var xml = "<library>" + "<book>" + "<name>Harry Potter</name>" + "</book>";
("</library>");

signXml(xml, "//*[local-name(.)='book']", "client.pem", "result.xml");

你总是可以把实际代码看成样本.

同步签名和核查

如果私密密钥不在本地存储,而您希望使用签名服务器或硬件安全模块(HSM)来签名文档,您可以创建一个使用同步回调的自定义签名算法.

function AsyncSignatureAlgorithm() {
  this.getSignature = function (signedInfo, privateKey, callback) {
    var signer = crypto.createSign("RSA-SHA1");
    signer.update(signedInfo);
    var res = signer.sign(privateKey, "base64");
    //Do some asynchronous things here
    callback(null, res);
  };
  this.getAlgorithmName = function () {
    return "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
  };
}

var sig = new SignedXml({ signatureAlgorithm: "http://asyncSignatureAlgorithm" });
sig.SignatureAlgorithms["http://asyncSignatureAlgorithm"] = AsyncSignatureAlgorithm;
sig.signatureAlgorithm = "http://asyncSignatureAlgorithm";
sig.canonicalizationAlgorithm = "http://www.w3.org/2001/10/xml-exc-c14n#";
sig.computeSignature(xml, opts, function (err) {
  var signedResponse = sig.getSignedXml();
});

职能 sig.checkSignature 如果需要同步核查,也可使用回调.

X.509 / 密钥格式

Xml-Crypto内部依赖于节点的加密模块. 这意味着pem被编码的证书被支持. 因此,要签署一个 xml 使用这样的 key. pem( 只显示密钥内容的开头) :

-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0...
-----END PRIVATE KEY-----

而用于验证的密钥 public.pem:

-----BEGIN CERTIFICATE-----
MIIBxDCCAW6gAwIBAgIQxUSX...
-----END CERTIFICATE-----

将 pfx 证书转换为 pem

如果您有 .pfx 证书, 您可以使用 打开数字 :

openssl pkcs12 -in c:\certs\yourcert.pfx -out c:\certs\cag.pem

那你可以用结果来签署 为验证目的,打开所生成的.pem并使用文本编辑器并复制自---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------.

实例

如何签名根节点( e)马上就来了(中文(简体) )

如何为签名添加前缀

使用 prefix 选项 computeSignature 为签名添加前缀.

var SignedXml = require("xml-crypto").SignedXml,
  fs = require("fs");

var xml = "<library>" + "<book>" + "<name>Harry Potter</name>" + "</book>" + "</library>";

var sig = new SignedXml({ privateKey: fs.readFileSync("client.pem") });
sig.addReference({
  xpath: "//*[local-name(.)='book']",
  digestAlgorithm: "http://www.w3.org/2000/09/xmldsig#sha1",
  transforms: ["http://www.w3.org/2001/10/xml-exc-c14n#"],
});
sig.canonicalizationAlgorithm = "http://www.w3.org/2001/10/xml-exc-c14n#";
sig.signatureAlgorithm = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
sig.computeSignature(xml, {
  prefix: "ds",
});

如何指定签名的位置

使用 location 选项 computeSignature 来移动签名. 设定 action 改为:

  • 附加( 默认) - 附加到 xml 文档的末尾
  • 预选 - 预选到 xml 文档
  • 前 - 预置到特定节点(使用 referenceNode (财产)
  • 在 - 附加到特定节点后(使用 referenceNode (财产)
var SignedXml = require("xml-crypto").SignedXml,
  fs = require("fs");

var xml = "<library>" + "<book>" + "<name>Harry Potter</name>" + "</book>" + "</library>";

var sig = new SignedXml({ privateKey: fs.readFileSync("client.pem") });
sig.addReference({
  xpath: "//*[local-name(.)='book']",
  digestAlgorithm: "http://www.w3.org/2000/09/xmldsig#sha1",
  transforms: ["http://www.w3.org/2001/10/xml-exc-c14n#"],
});
sig.canonicalizationAlgorithm = "http://www.w3.org/2001/10/xml-exc-c14n#";
sig.signatureAlgorithm = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
sig.computeSignature(xml, {
  location: { reference: "//*[local-name(.)='book']", action: "after" }, //This will place the signature after the book element
});

更多实例(马上就来了(中文(简体) )

发展

我们使用的测试框架是 摩诃迦叶 与 柴仔 作为主张框架.

测试使用:

npm test

更多信息

拜访我 博客 还是我的 推特上说

Bitdeli Badge

许可证

本项目根据以下规定获得许可证: MIT 许可证见 自由主义 需要更多信息的文件.

版本与发布记录

@boxyhq/xml-crypto 共发布 2 个版本,首次发布于 2025/03/09;过去 12 个月发布了 0 个版本。

版本发布日期距今
6.1.0latest2025/03/141.7 年前
6.0.12025/03/091.7 年前

关于 @boxyhq/xml-crypto 的常见问题

@boxyhq/xml-crypto 是什么?

Xml 节点.js 的数字签名和加密库

如何安装 @boxyhq/xml-crypto?

在项目目录运行 npm install @boxyhq/xml-crypto,或使用 pnpm add / yarn add / bun add。

@boxyhq/xml-crypto 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/boxyhq__xml-crypto 是否存在。

@boxyhq/xml-crypto 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@boxyhq/xml-crypto 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=16。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@boxyhq/xml-crypto 可以商用吗?

@boxyhq/xml-crypto 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@boxyhq/xml-crypto 的下载量有多少?

根据 npm 官方下载统计,@boxyhq/xml-crypto 在 2026/10/09 – 2026/11/07 这 30 天内被下载 4,526 次,日均约 151 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@boxyhq/xml-crypto 还在维护吗?

最新版本 6.1.0 发布于 2025/03/14(1.7 年前);至今共发布 2 个版本,其中过去 12 个月发布了 0 个;首次发布于 2025/03/09。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。