首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >java.security.SignatureException:用于签名的无效编码。由Azure验证的签名

java.security.SignatureException:用于签名的无效编码。由Azure验证的签名
EN

Stack Overflow用户
提问于 2019-06-30 12:40:46
回答 3查看 4.5K关注 0票数 2

当使用Signature.verify验证签名时,我会收到一个“签名编码无效”的异常。使用Azure服务验证相同签名时,将验证签名。

我有一个散列数据(SHA-256)、一个公钥和一个我正在试图验证的签名。签名采用com.microsoft.azure.keyvault.KeyVaultClient.sign方法,签名算法为"ES256“。

这是可行的(使用ES256算法):

代码语言:javascript
复制
    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密钥库中的相同公钥):

代码语言:javascript
复制
    Signature ecdsaSign = Signature.getInstance("SHA256withECDSA");
    ecdsaSign.initVerify(certificate.getPublicKey());
    ecdsaSign.update(hashData);
    ecdsaSign.verify(signature)

预期结果-真(签名被验证)

实际结果:

代码语言:javascript
复制
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)
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-07-01 17:04:55

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

代码语言:javascript
复制
    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);

在格式更改之后,我没有得到“序列标记错误”异常。但核查仍然失败。

谢谢!

票数 1
EN

Stack Overflow用户

发布于 2019-06-30 20:39:57

Azure使用,它简单地连接固定大小的r和s的I2OSP。,但是Java和大多数但不是所有标准一样,使用ASN.1 DER编码例如rfc3279 (警告:现在有其他哈希用于ECDSA的OID)。

要将JWS/平原转换为DER,请参阅我的(交叉) https://security.stackexchange.com/questions/174095/convert-ecdsa-signature-from-plain-to-der-format中的C方法,但是Java使其更容易,因为BigInteger为您完成了一半的工作:

代码语言:javascript
复制
// 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;

2020-05更正并添加:Java9up也直接使用诸如SHA256withECDSAinP1363format之类的algoirthm名称来处理这个问题,而在所有版本的BouncyCastle上,它都使用SHA256withPLAIN-ECDSASHA256withCVC-ECDSA这样的名称进行处理。见如何为java.security.Signature符号方法指定签名长度长度不一致的Java ECDSAwithSHA256签名

票数 1
EN

Stack Overflow用户

发布于 2022-07-19 13:34:58

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

代码语言:javascript
复制
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();
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56824921

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档