无法核查的OpenSSL与DSA密钥签名的串(unable to verify string sig

2019-09-27 17:39发布

在适应的方向从Linux命令行创建DSA签名我创建了一个DSA签名的消息:

echo "foobar" > foo.txt
openssl dgst -dss1 -sign dsa_priv.pem foo.txt > sigfile.bin

该方向实际使用foo.sha1代替foo.txt的,其中由产生foo.sha1 sha1sum但签署的哈希似乎有点多余,因为DSA是本身应该做的散列。

所以,无论如何,我做到了。 下面是我使用的私钥(我产生它专门用于测试目的):

-----BEGIN DSA PRIVATE KEY-----
MIIBvAIBAAKBgQDsGAHAM16bsPlwl7jaec4QMynYa0YLiLiOZC4mvH4UW/tRJxTz
aV7eH1EtnP9D9J78x/07wKYs8zJEWCXmuq0UluQfjA47+pb68b/ucQTNeZHboNN9
5oEi+8BCSK0y8G3uf3Y89qHvqa9Si6rP374MinEMrbVFm+UpsGflFcd83wIVALtJ
ANi+lYG7xMKQ/bE4+bS8gemNAoGBAORowvirD7AB9x2SpdiME41+O4jVR8rs6+GX
Ml3Hif6Yt1kem0CeraX9SNoyBNAzjD5TVMGIdGlgRr6GNreHeXMGWlvdDkvCACER
ZEEtMsKZicm+yl6kR8AGHTCA/PBltHfyrFQd4n9I//UDqI4RjqzvpCXGQcVEsSDY
CCBGBQJRAoGBALnHTAZlpoLJZuSBVtnMuRM3cSX43IkE9w9FveDV1jX5mmfK7yBV
pQFV8eVJfk91ERQ4Dn6ePLUv2dRIt4a0S0qHqadgzyoFyqkmmUi1kNLyixtRqh+m
2gXx0t63HEpZDbEPppdpnlppZquVQh7TyrKSXW9MTzUkQjFI9UY7kZeKAhQXiJgI
kBniZHdFBAZBTE14YJUBkw==
-----END DSA PRIVATE KEY-----

这里是十六进制编码输出sigfile.bin

302c021456d7e7da10d1538a6cd45dcb2b0ce15c28bac03402147e973a4de1e92e8a87ed5218c797952a3f854df5

现在我想在Java中与BouncyCastle的验证这一点,我不能这样做。 这是我的Java代码:

import java.io.StringReader;
import org.bouncycastle.openssl.PEMReader;
import java.security.interfaces.DSAPublicKey;
import org.bouncycastle.crypto.params.DSAPublicKeyParameters;

import org.bouncycastle.crypto.signers.DSADigestSigner;
import org.bouncycastle.crypto.signers.DSASigner;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.params.DSAParameters;

public class DSA
{
    public static void main(String[] args)
    throws Exception
    {
        byte[] message = "foobar".getBytes();
        byte[] signature = hexStringToByteArray("302c021456d7e7da10d1538a6cd45dcb2b0ce15c28bac03402147e973a4de1e92e8a87ed5218c797952a3f854df5");

            String key = "-----BEGIN PUBLIC KEY-----\n" +
                "MIIBuDCCASwGByqGSM44BAEwggEfAoGBAOwYAcAzXpuw+XCXuNp5zhAzKdhrRguI\n" +
                "uI5kLia8fhRb+1EnFPNpXt4fUS2c/0P0nvzH/TvApizzMkRYJea6rRSW5B+MDjv6\n" +
                "lvrxv+5xBM15kdug033mgSL7wEJIrTLwbe5/djz2oe+pr1KLqs/fvgyKcQyttUWb\n" +
                "5SmwZ+UVx3zfAhUAu0kA2L6VgbvEwpD9sTj5tLyB6Y0CgYEA5GjC+KsPsAH3HZKl\n" +
                "2IwTjX47iNVHyuzr4ZcyXceJ/pi3WR6bQJ6tpf1I2jIE0DOMPlNUwYh0aWBGvoY2\n" +
                "t4d5cwZaW90OS8IAIRFkQS0ywpmJyb7KXqRHwAYdMID88GW0d/KsVB3if0j/9QOo\n" +
                "jhGOrO+kJcZBxUSxINgIIEYFAlEDgYUAAoGBALnHTAZlpoLJZuSBVtnMuRM3cSX4\n" +
                "3IkE9w9FveDV1jX5mmfK7yBVpQFV8eVJfk91ERQ4Dn6ePLUv2dRIt4a0S0qHqadg\n" +
                "zyoFyqkmmUi1kNLyixtRqh+m2gXx0t63HEpZDbEPppdpnlppZquVQh7TyrKSXW9M\n" +
                "TzUkQjFI9UY7kZeK\n" +
                "-----END PUBLIC KEY-----";
        PEMReader reader = new PEMReader(new StringReader(key));
        DSAPublicKey decoded = (DSAPublicKey) reader.readObject();

        DSADigestSigner dsa = new DSADigestSigner(new DSASigner(), new SHA1Digest());
        DSAParameters params = new DSAParameters(
            decoded.getParams().getP(),
            decoded.getParams().getQ(),
            decoded.getParams().getG()
        );
        DSAPublicKeyParameters publickey = new DSAPublicKeyParameters(decoded.getY(), params);
        dsa.init(false, publickey);
        dsa.update(message, 0, message.length);
        boolean result = dsa.verifySignature(signature);

        System.out.println(result ? "good" : "bad");
    }

    public static byte[] hexStringToByteArray(String s)
    {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2)
        {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                + Character.digit(s.charAt(i+1), 16));
        }
        return data;
    }
}

签名不验证。 是不是有什么毛病我的Java代码? 也许OpenSSL是做一些奇怪的与DSS1?

我能够验证签名就好了使用OpenSSL:

openssl dgst -dss1 -verify dsa_pub.pem -signature sigfile.bin foo.txt

Answer 1:

(UNIX) echo输出如果多于一个其参数,空间分隔加上一个换行 。 使用"foobar\n" ,以验证数据。 可替换地签署的结果printf '%s' foobar >foo.txt哪个便携省略了换行; 某些版本的echo支持-n为此,一些旧的使用\c ,有的不支持它。

FYI BouncyCastle的作为版本150(2013)不再具有org.bouncycastle.openssl.PEMReader ; 相反,你需要PEMParser返回org.bouncycastle.asn1.x509.SubjectPublicKeyInfo可以通过转换为重点对象org.bouncycastle.openssl.jcajce.JcaPEMKeyConverterKeyFactory.getInstance(alg).generatePublicKey(new X509EncodedKey(spki.getEncoded()))这是什么JcaPEMKeyConverter实际上做。

OTOH,你可以使用org.bouncycastle.jcajce.provider.asymmetric.dsa.DSAUtil.generatePublicKeyParameter来替换与参数摆弄件; 这就是公元前提供商接口(而不是轻量级接口)一样。 或者,你当然可以只使用JCA摆在首位,你真的不需要BC可言,因为OpenSSL的公钥格式(不像专用密钥)是基本的Java加密一贯兼容。

另外顺便说一句openssl dgst需要-dss1只能通过0.9.8版本破解; 自1.0.0版本发布的2010年(而不是立即被许多发行版和产品,由于实际的或担心不兼容的升级),你只需要-sha1和DSA PUBKEY。



文章来源: unable to verify string signed by openssl with dsa key