为了账号安全,请及时绑定邮箱和手机立即绑定

java.security.SignatureException:签名编码无效。

java.security.SignatureException:签名编码无效。

千巷猫影 2023-02-23 18:21:17
使用 Signature.verify 验证签名时,我收到“签名的无效编码”异常。使用 Azure 服务验证相同签名时,将验证签名。我有一个散列数据 (SHA-256)、一个公钥和一个我要验证的签名。使用 com.microsoft.azure.keyvault.KeyVaultClient.sign 方法接收签名,签名算法为“ES256”。这有效(使用 ES256 算法):    com.microsoft.azure.keyvault.KeyVaultClient keyVaultClient;    String keyPairIdentifier;    boolean verify(byte[] hashData, byte[] signature, JsonWebKeySignatureAlgorithm signingAlgorithm) {        com.microsoft.azure.keyvault.models.KeyVerifyResult result = keyVaultClient.verify(keyPairIdentifier, signingAlgorithm, hashData, signature);        return result.value().booleanValue();    }这失败了(证书持有存储在 Azure keyvault 中的相同公钥):    Signature ecdsaSign = Signature.getInstance("SHA256withECDSA");    ecdsaSign.initVerify(certificate.getPublicKey());    ecdsaSign.update(hashData);    ecdsaSign.verify(signature)预期结果 - true(签名已验证)实际结果:java.security.SignatureException: Could not verify signature    at sun.security.ec.ECDSASignature.engineVerify(ECDSASignature.java:325)    at java.security.Signature$Delegate.engineVerify(Signature.java:1222)    at java.security.Signature.verify(Signature.java:655)    at TestKV.KeyVault.VerifyDPSignature.verifySignatureUsingCertificate(VerifyDPSignature.java:143)    at TestKV.KeyVault.VerifyDPSignature.main(VerifyDPSignature.java:104)Caused by: java.security.SignatureException: Invalid encoding for signature    at sun.security.ec.ECDSASignature.decodeSignature(ECDSASignature.java:400)    at sun.security.ec.ECDSASignature.engineVerify(ECDSASignature.java:322)    ... 4 more Caused by: java.io.IOException: Sequence tag error    at sun.security.util.DerInputStream.getSequence(DerInputStream.java:330)    at sun.security.ec.ECDSASignature.decodeSignature (ECDSASignature.java:376)
查看完整描述

3 回答

?
湖上湖

TA贡献2003条经验 获得超2个赞

Azure 的 JWS只是连接固定大小的 r 和 s 的 I2OSP,但 Java JCE 与大多数但不是所有标准一样,使用 ASN.1 DER 编码,例如 rfc3279(注意:现在有用于 ECDSA 的 OID 和其他哈希值)。

要将 JWS/plain 转换为 DER,请参阅我的(交叉)https://security.stackexchange.com/questions/174095/convert-ecdsa-signature-from-plain-to-der-format以获得 C 方法,但 Java 使它更容易,因为BigInteger为你做了一半的工作:

// byte[64] plain contains the JWS-style r,s (de-base64-ed if necessary)

byte[] r = new BigInteger(1,Arrays.copyOfRange(plain,0,32)).toByteArray();

byte[] s = new BigInteger(1,Arrays.copyOfRange(plain,32,64)).toByteArray();

byte[] der = new byte[6+r.length+s.length]; der[0] = 0x30; der[1] = der.length-2; int o = 2;

der[o++] = 2; der[o++] = (byte)r.length; System.arraycopy (r,0, der,o, r.length); o+=r.length;

der[o++] = 2; der[o++] = (byte)s.length; System.arraycopy (s,0, der,o, s.length); //o+=s.length;

更正并添加: Java 9 向上也使用诸如 之类的算法名称直接处理此问题SHA256withECDSAinP1363format,并且在所有版本的 Java 上,如果您添加 BouncyCastle,它会使用诸如SHA256withPLAIN-ECDSA或 之类的名称来处理此问题SHA256withCVC-ECDSA。看java.security.Signature签名方法和Java ECDSAwithSHA256签名长度不一致如何指定签名长度

查看完整回答
反对 回复 2023-02-23
?
千万里不及你

TA贡献1784条经验 获得超9个赞

dave_thompson_085 - 谢谢!你附上的代码有一些错误,签名部分的标签应该是0x02,而不是0x30,而且你复制第一部分后没有增加o。这是更改后的代码:


    byte[] r = new BigInteger(1,Arrays.copyOfRange(signature,0,32)).toByteArray();

    byte[] s = new BigInteger(1,Arrays.copyOfRange(signature,32,64)).toByteArray();

    byte[] der = new byte[6+r.length+s.length];

    der[0] = 0x30; // Tag of signature object

    der[1] = (byte)(der.length-2); // Length of signature object

    int o = 2;

    der[o++] = 0x02; // Tag of ASN1 Integer

    der[o++] = (byte)r.length; // Length of first signature part

    System.arraycopy (r,0, der,o, r.length);

    o += r.length;

    der[o++] = 0x02; // Tag of ASN1 Integer

    der[o++] = (byte)s.length; // Length of second signature part

    System.arraycopy (s,0, der,o, s.length);

格式更改后,我没有得到“序列标记错误”异常。但是验证还是失败了。


查看完整回答
反对 回复 2023-02-23
?
精慕HU

TA贡献1845条经验 获得超8个赞

在我的例子中,我只需要先将签名的原始字节解码为 Base64。


byte[] signatureBytes = Base64.getDecoder().decode(signature.getBytes());    

byte[] r = new BigInteger(1,Arrays.copyOfRange(signatureBytes,0,32)).toByteArray();    

byte[] s = new BigInteger(1,Arrays.copyOfRange(signatureBytes,32,64)).toByteArray();



查看完整回答
反对 回复 2023-02-23
  • 3 回答
  • 0 关注
  • 1012 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信