错误信息
Invalid key object type public, expected private.
消息中的两个名词会随密钥和操作而变化:用对称密钥调用 sign() 时报告“Invalid key object type secret, expected private.”,用对称密钥调用 verify() 时报告“Invalid key object type secret, expected private or public.”。verify() 本身接受私钥,并用其中的公钥部分验证。消息的结构是固定的。
Node.js crypto — TypeError, code ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE
含义
你传入的 KeyObject 类型不适用于这个操作:crypto.sign() 需要私钥,却收到了公钥(或者 verify() 收到了对称密钥,等等)。Node 的密钥对象知道自己的类型——公钥(public)、私钥(private)或对称密钥(secret)——每个 API 只接受特定的类型。
原因
调用处把变量弄反了
常见解构时把 publicKey 和 privateKey 写反了,或者名为 key 的函数参数收到的是调用方手头碰巧有的那个密钥。用公钥签名从原理上就不可能,Node 会直接指出这一点,而不是等到后面莫名其妙地失败。
加载得到的类型与预想的不同
常见createPublicKey(privatePem) 按设计就会派生出公钥——之后把结果当作私钥用来签名的代码会在这里失败。同样,实际包含公钥的 PEM 文件,不管文件名怎么写,加载后的类型都是“public”。
把对称密钥(secret)用在了非对称 API 中
偶见把 createSecretKey() 的输出(HMAC/AES 密钥)传给了用于 ECDSA 的 sign/verify。对称密钥材料无法参与公钥签名。
修复方法
- 1.
在边界处断言密钥类型
KeyObject.type 的取值为 "public" | "private" | "secret"。一行断言就能把令人困惑的 crypto 错误,变成加载时一眼就能看懂的错误。
js import { createPrivateKey } from "node:crypto"; const signingKey = createPrivateKey(pem); if (signingKey.type !== "private") { throw new Error(`expected private key, got ${signingKey.type}`); } - 2.
让密钥对的两半各司其职
私钥签名,公钥验证。如果手里只有私钥,就从中派生出公钥用于验证,而不是到处复用私钥对象。
js import { createPublicKey, sign, verify } from "node:crypto"; const signature = sign("sha256", data, privateKey); // private → sign const publicKey = createPublicKey(privateKey); // derive public half const ok = verify("sha256", data, publicKey, signature); // public → verify