Java 无法验证openssl使用dsa密钥签名的字符串
在我创建DSA签名消息时调整方向:Java 无法验证openssl使用dsa密钥签名的字符串,java,openssl,bouncycastle,public-key-encryption,dsa,Java,Openssl,Bouncycastle,Public Key Encryption,Dsa,在我创建DSA签名消息时调整方向: echo "foobar" > foo.txt openssl dgst -dss1 -sign dsa_priv.pem foo.txt > sigfile.bin directions实际上使用了foo.sha1而不是foo.txt,其中foo.sha1是由sha1sum生成的,但签名哈希似乎有点多余,因为DSA本身应该进行哈希运算 所以,不管怎样,我做到了。以下是我使用的私钥(我专门为测试目的生成它): 下面是sigfile.bin的十六进
echo "foobar" > foo.txt
openssl dgst -dss1 -sign dsa_priv.pem foo.txt > sigfile.bin
directions实际上使用了foo.sha1而不是foo.txt,其中foo.sha1是由sha1sum
生成的,但签名哈希似乎有点多余,因为DSA本身应该进行哈希运算
所以,不管怎样,我做到了。以下是我使用的私钥(我专门为测试目的生成它):
下面是sigfile.bin的十六进制编码输出:
302c021456d7e7da10d1538a6cd45dcb2b0ce15c28bac03402147e973a4de1e92e8a87ed5218c797952a3f854df5
我现在正试图用BouncyCastle在Java中验证这一点,但无法做到。以下是我的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;
}
}
(Unix)echo
输出其参数,如果有多个参数,则以空格分隔,加上换行符。使用“foobar\n”
作为验证数据。或者对printf“%s”foobar>foo.txt的结果进行签名,该结果可移植地忽略换行符;有些版本的echo
支持-n
为此,有些旧版本使用\c
,有些根本不支持
自版本150(2013)起的FYI BouncyCastle不再具有org.BouncyCastle.openssl.PEMReader
;相反,您需要PEMParser
,它返回org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
,可以通过org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter
或KeyFactory.getInstance(alg).生成PublicKey(新的X509EncodedKey(spki.getEncoded()))
这就是JcaPEMKeyConverter的实际功能
o您可以使用org.bouncycastle.jcajce.provider.asymetric.dsa.DSAUtil.generatePubliceParameter
替换对参数片段的篡改;这就是BC提供程序接口(与轻量级接口相反)的功能。当然,您也可以首先使用JCA,而实际上根本不需要BC,因为OpenSSL公钥格式(与privatekey不同)与基本Java加密一致兼容
另外,顺便说一句,openssl dgst
只需要通过版本0.9.8进行-dss1
黑客攻击;自2010年1.0.0版发布以来(但由于实际或担心不兼容,许多发行版和产品没有立即升级),您只需要-sha1
和DSA公钥
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;
}
}
openssl dgst -dss1 -verify dsa_pub.pem -signature sigfile.bin foo.txt