【问题标题】:Difference between Go DSA and Java DSA [closed]Go DSA 和 Java DSA 之间的区别 [关闭]
【发布时间】:2021-10-30 17:12:09
【问题描述】:
  1. Go 使用 DSA 私钥生成签名
  2. Java 使用 DSA 公钥验证第一步结果
  3. Java 应该返回 true,但返回 false
package main
import (
    "crypto/dsa"
    "crypto/rand"
    "encoding/asn1"
    "encoding/hex"
    "fmt"
    "golang.org/x/crypto/ssh"
    "math/big"
)

func main() {
    // a dsa private key
    pemData := []byte("-----BEGIN DSA PRIVATE KEY-----\n" +
        "MIIBvAIBAAKBgQD9f1OBHXUSKVLfSpwu7OTn9hG3UjzvRADDHj+AtlEmaUVdQCJR\n" +
        "+1k9jVj6v8X1ujD2y5tVbNeBO4AdNG/yZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb\n" +
        "+DtX58aophUPBPuD9tPFHsMCNVQTWhaRMvZ1864rYdcq7/IiAxmd0UgBxwIVAJdg\n" +
        "UI8VIwvMspK5gqLrhAvwWBz1AoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlX\n" +
        "TAs9B4JnUVlXjrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCj\n" +
        "rh4rs6Z1kW6jfwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtVJWQB\n" +
        "TDv+z0kqAoGBAIb9o0KPsjAdzjK571e1Mx7ZhEyJGrcxHiN2sW8IztEbqrKKiMxp\n" +
        "NlTwm234uBdtzVHE3uDWZpfHPMIRmwBjCYDFRowWWVRdhdFXZlpCyp1gMWqJ11dh\n" +
        "3FI3+O43DevRSyyuLRVCNQ1J3iVgwY5ndRpZU7n6y8DPH4/4EBT7KvnVAhR4Vwun\n" +
        "Fhu/+4AGaVeMEa814I3dqg==\n" +
        "-----END DSA PRIVATE KEY-----")
    // parse dsa 
    p, _ := ssh.ParseRawPrivateKey(pemData)
    pp := p.(*dsa.PrivateKey)

    // orign data
    hashed := []byte{1}
    r, s, _ := dsa.Sign(rand.Reader, pp, hashed)

    type dsaSignature struct {
        R, S *big.Int
    }
    var ss dsaSignature
    ss.S = s
    ss.R = r
    signatureBytes, _ := asn1.Marshal(ss)

    // print sign 
    fmt.Println(hex.EncodeToString(signatureBytes))
}
  1. Java 读取 DSA 公钥并初始化签名者
  2. Java 验证第一步签名结果
  3. 返回 false
@Test
public void ttt() throws InvalidKeySpecException, NoSuchAlgorithmException, InvalidKeyException, SignatureException {
        // DSA public key
        String pubKey = "-----BEGIN PUBLIC KEY-----\n" +
                "MIIBuDCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9E\n" +
                "AMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f\n" +
                "6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv\n" +
                "8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtc\n" +
                "NrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwky\n" +
                "jMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/h\n" +
                "WuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYUAAoGBAIb9o0KPsjAdzjK571e1Mx7ZhEyJ\n" +
                "GrcxHiN2sW8IztEbqrKKiMxpNlTwm234uBdtzVHE3uDWZpfHPMIRmwBjCYDFRowW\n" +
                "WVRdhdFXZlpCyp1gMWqJ11dh3FI3+O43DevRSyyuLRVCNQ1J3iVgwY5ndRpZU7n6\n" +
                "y8DPH4/4EBT7KvnV\n" +
                "-----END PUBLIC KEY-----";
        String publicKeyPEM = pubKey
                .replace("-----BEGIN PUBLIC KEY-----\n", "")
                .replaceAll(System.lineSeparator(), "")
                .replace("-----END PUBLIC KEY-----", "");
        byte[] publicEncoded = Base64.decodeBase64(publicKeyPEM);
        KeyFactory keyFactory1 = KeyFactory.getInstance("DSA");
        X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicEncoded);
        DSAPublicKey pubKeyy = (DSAPublicKey) keyFactory1.generatePublic(publicKeySpec);

        // init signer
        Signature sig1 = Signature.getInstance("DSA");
        sig1.initVerify(pubKeyy);
        sig1.update(new byte[]{1});
        
        // verify first result
        System.out.println(sig1.verify(HexUtil.decodeHex("first step result")));
}


  1. 我想在 Java 实现中使用 NONEwithDSA,但没有这样做
  2. 签名 sig1 = Signature.getInstance("NONEwithDSA");
java.security.SignatureException: Data for RawDSA must be exactly 20 bytes long

  1. 我想在 Java 实现中使用 SHA1withDSA,但没有这样做
  2. 签名 sig1 = Signature.getInstance("SHA1withDSA");
  3. 返回错误

【问题讨论】:

  • 您的 golang 签名是“原始/普通”r|s 格式,但 Java 需要“DER”编码。对于 Java,您需要将签名转换为 DER 格式或直接以 DER 编码生成 golang 签名[因为我不是 DSA 签名方面的专家,我无法进一步帮助您,抱歉。]
  • @MichaelFehr:我不这么认为。虽然 OP 没有发布数据,我也不是一个旁观者(更像是一个停止者) asn1.Marshal 在我看来就像会生成 DER 的东西,在我的测试中,SUN 和 BC 提供者都为非 DER 签名抛出异常,它们不会像发布的那样返回 false。

标签: java go dsa


【解决方案1】:

在 Java 中,(签名)算法名称 DSASHA1withDSA 的别名,即原始 FIPS186-0 算法。这与显然由 Go 实现的非标准“原始”原语不同。 NONEwithDSA 确实是您想要的正确 Java 名称,但“标准”(SUN) 提供程序中的实现有点像需要 20 个字节的数据,而不是更多或更少,因为那是SHA1 哈希,它是 FIPS186-3 之前 DSA 的唯一标准哈希。

如果您(拥有或可以获得并)使用 BouncyCastle 提供程序,则它没有此限制,并且应该适用于您更改为 NONEwithDSA 的代码(以及代码或安全配置修改,以便选择 BC 作为提供者,当然)。

如果你不使用 Bouncy,我认为你必须自己编写算法;我认为没有任何方法可以让 SUN 实现做你想做的事。

虽然更好按照标准指定的适当大小的哈希而不是原始数据进行签名,然后您可以使用指定和设计的 Java 提供程序。

【讨论】:

  • 我使用 golang sha1 orign data hashed := []byte{1} sha1 := sha1.New() sha1.Write(hashed) hashed = sha1.Sum(nil) 和 java 使用 Signature sig1 = Signature.getInstance("DSA");可以通过
猜你喜欢
  • 2011-02-19
  • 1970-01-01
  • 2012-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-04
  • 1970-01-01
  • 2012-10-09
相关资源
最近更新 更多