Tink 用密钥集取代单个密钥——密钥集是一组带 ID 的密钥,其中一个被标记为主密钥——并用 ECDSA_P256、ED25519 等具名模板取代算法。原语(PublicKeySign、PublicKeyVerify)会透明地轮换密钥,这正是该设计的目的,也是互操作时种种意外的根源。密钥集以 Tink JSON 或二进制 protobuf 格式存储,而不是 PEM。
默认的 ECDSA_P256 模板会在签名前加上输出前缀:0x01 和 4 字节的密钥 ID,后面才是 DER 签名。JDK 拒绝了这样的签名,报错 Invalid encoding for signature,所有非 Tink 的验证方都会如此。以 _WITHOUT_PREFIX 或 _RAW 结尾的模板会去掉前缀,但名称同样看不出编码:ECDSA_P256_RAW 生成的是 64 字节的 IEEE P1363 r‖s,而不是 DER——它用 JDK 的 SHA256withECDSAinP1363Format 验证通过,用 SHA256withECDSA 则验证失败。应按对端要求的确切编码选择模板,就像示例使用 ECDSA_P256_IEEE_P1363_WITHOUT_PREFIX 那样,并用 DER ⇄ 原始格式转换器检查字节。
导入外部公钥要经过 SignaturePemKeysetReader,得到的密钥只能验证 DER 签名:同一个原始签名,Tink 自己的 P1363 密钥接受了它,用从 PEM 导入的密钥验证却失败,直到将其重新编码为 DER。签名使用随机 nonce,s 没有经过规范化,验证时接受 high-S;无效输入会抛出 GeneralSecurityException: invalid signature。
Java 版 Tink 1.24.0 提供 P-256、P-384 和 P-521 上的 ECDSA、Ed25519 以及 RSA(PKCS#1 v1.5 和 PSS)模板;该版本中没有注册任何 ML-DSA 或 SLH-DSA 模板(Name ML_DSA_65 does not exist)。目前要在 JVM 上使用后量子签名,可参阅 Java JCA 或 Bouncy Castle。