Go DSA和Java DSA之间的区别是什么?

huangapple go评论100阅读模式
英文:

Difference between Go DSA and Java DSA

问题

  1. Go使用DSA私钥生成签名。
  2. Java使用DSA公钥验证第一步的结果。
  3. Java应该返回true,但返回了false。
@Test
public void ttt() throws InvalidKeySpecException, NoSuchAlgorithmException, InvalidKeyException, SignatureException {
    // DSA公钥
    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);

    // 初始化签名器
    Signature sig1 = Signature.getInstance("DSA");
    sig1.initVerify(pubKeyy);
    sig1.update(new byte[]{1});

    // 验证第一步结果
    System.out.println(sig1.verify(HexUtil.decodeHex("first step result")));
}
  1. 我尝试在Java实现中使用NONEwithDSA,但没有成功。
  2. Signature sig1 = Signature.getInstance("NONEwithDSA");
java.security.SignatureException: Data for RawDSA must be exactly 20 bytes long
  1. 我尝试在Java实现中使用SHA1withDSA,但没有成功。
  2. Signature sig1 = Signature.getInstance("SHA1withDSA");
  3. 返回false。
英文:
  1. Go generates a signature using a DSA private key
  2. Java verifies first step result using the DSA public key
  3. Java should return true, but returns 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 reads the DSA public key and initialize a signer
  2. Java verify first step sign result
  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. i tred to use NONEwithDSA within the Java implementation but it didnt do it
  2. Signature sig1 = Signature.getInstance("NONEwithDSA");
java.security.SignatureException: Data for RawDSA must be exactly 20 bytes long

  1. i tred to use SHA1withDSA within the Java implementation but it didnt do it
  2. Signature sig1 = Signature.getInstance("SHA1withDSA");
  3. returns false

答案1

得分: 2

在Java中,(Signature)算法名称DSASHA1withDSA的别名,即原始的FIPS186-0算法。这与Go中显然实现的非标准的'raw'原语不同。NONEwithDSA确实是你想要的正确的Java名称,但是'Standard' (SUN)提供程序中的实现有些笨拙,需要确切地20个字节的数据,不能多也不能少,因为在FIPS186-3之前,SHA1哈希是DSA的唯一标准哈希,其大小正好是20个字节。

如果你使用_BouncyCastle_提供程序(如果你有或者可以获取),它没有这个限制,并且应该可以适用于你将代码更改为NONEwithDSA的情况(当然,你需要修改代码或安全配置以选择BC作为提供程序)。

如果你不使用Bouncy,我认为你将不得不自己编写算法;我认为没有办法让SUN的实现做你想要的事情。

虽然按照标准规定,签名一个正确大小的哈希而不是原始数据会更好,这样你就可以按照规定和设计使用Java提供程序。

英文:

In Java the (Signature) algorithm name DSA is an alias for SHA1withDSA, i.e. the original FIPS186-0 algorithm. This is not the same as the nonstandard 'raw' primitive apparently implemented by Go. NONEwithDSA is indeed the correct Java name for what you want, but the implementation in the 'standard' (SUN) provider is something of a kludge that requires exactly 20 bytes of data, not more or less, because that was the size of the SHA1 hash which was the only standard hash for DSA prior to FIPS186-3.

If you (have or can get and) use the BouncyCastle provider, it does not have this restriction, and should work for your code changed to NONEwithDSA (and either the code or security config modified so that BC is selected as the provider, of course).

If you don't use Bouncy, I think you'll have to code the algorithm yourself; I don't think there's any way to get the SUN implementation to do what you want.

Although it would be better to sign a properly-sized hash as specified in the standard, not raw data, and then you could use the Java providers as specified and designed.

huangapple
  • 本文由 发表于 2021年9月1日 15:44:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/69009710.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定