Go DSA 和 Java DSA 之间的区别

Difference between Go DSA and Java DSA

  1. Go 使用 DSA 私钥生成签名
  2. Java 使用 DSA public 密钥验证第一步结果
  3. Java 应该 return 正确,但 return 错误
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 public 密钥并初始化签名者
  2. Java验证第一步签名结果
  3. returns 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. return假

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

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

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

虽然 更好 签署标准中指定的适当大小的散列,而不是原始数据,然后您可以使用 Java 提供商作为指定和设计。