【问题标题】:java.security.SignatureException: Invalid encoding for signature. signature validated by Azurejava.security.SignatureException:签名的编码无效。 Azure 验证的签名
【发布时间】:2019-06-30 12:40:46
【问题描述】:

使用 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 密钥库中的相同公钥):

    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)

【问题讨论】:

    标签: java azure signature


    【解决方案1】:

    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);
    

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

    谢谢!

    【讨论】:

    • 它适用于验证原始数据而不是散列:ecdsaSign.update(data);
    【解决方案2】:

    Azure 使用 JWS which simply concatenates fixed-size I2OSP of r and s,但 Java JCE 与大多数但不是所有标准一样,使用 ASN.1 DER 编码 e.g. 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;
    

    2020-05 已更正并添加: Java 9 up 也直接使用 SHA256withECDSAinP1363format 之类的算法名称处理此问题,并且在所有 Java 版本中,如果您添加 BouncyCastle,它会使用诸如 @987654329 之类的名称来处理此问题@ 或 SHA256withCVC-ECDSA。见how to specify signature length for java.security.Signature sign methodJava ECDSAwithSHA256 signature with inconsistent length

    【讨论】: