java如何在openssl中验证由ECDSA[r,s]值组成的签名?
我使用Bouncy Castle/Java生成签名,因为它给出了两个带R,S值的大整数。现在的要求是使用OpenSSL命令验证
public static String[] generateSignature(String message) {
final ECDSASigner ecdsaSigner = new ECDSASigner();
try {
// Get private key
BCECPrivateKey ecPrivateKey = (BCECPrivateKey) JKSUtil.getPrivateKey();
if(ecPrivateKey != null) {
// Get parameter spec from private key
ECParameterSpec ecSpec = ecPrivateKey.getParameters();
// Create ECDomain object
ECDomainParameters params = new ECDomainParameters(ecSpec.getCurve(), ecSpec.getG(), // G
ecSpec.getN()); // n
// Create private key parameters
ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(ecPrivateKey.getD(), // d
params);
ecdsaSigner.init(true, priKey);
// Create digest message (hash) for the actual message.
SHA256Digest keyDigest = new SHA256Digest();
keyDigest.update(message.getBytes(), 0, message.getBytes().length);
byte[] digestMessage = new byte[keyDigest.getDigestSize()];
keyDigest.doFinal(digestMessage, 0);
BigInteger[] sig = ecdsaSigner.generateSignature(digestMessage);
// Convert signature to base64
String[] base64Sig = new String[2];
base64Sig[0] = new String(Base64.encodeBase64(sig[0].toByteArray()));
base64Sig[1] = new String(Base64.encodeBase64(sig[1].toByteArray()));
String signature = base64Sig[0]+"|"+base64Sig[1];
System.out.println(signature);
return base64Sig;
}
} catch (Exception e) {
}
return null;
}
例如:我要签名的消息是"Name is RS"
,运行上面的实用程序会将带分隔符“|”的R和S值返回给我,分隔符在base64中编码为
ALk8VQP5XLmCIe0Kh3IE74fS55huvzv0jw==|Hj+UsStEbDYOqX98EszSET2ULE3D9kCV
现在在openssl方面:
openssl enc -base64 -d -in signature.txt -out signatureToVerify.bin -A
openssl dgst -sha256 -verify eckey.pub -signature signatureToVerify.bin message.txt
它无法验证,我被卡住了——在openssl端不断地将错误作为“验证失败”
# 1 楼答案
OpenSSL需要一个X9。62签名。这包括两个整数值R和S的DER编码。如果查看提供者类
SignatureSpi
的Bouncy Castle源代码,您将发现:这就是你应该使用Bouncy Castle对签名进行编码的地方。这里
r
和s
应该是在两元素结果数组中获得的BigInteger
值正如您可能猜到的,您也可以使用JavaJCA
Signature
类,它将生成相同的签名编码。如果需要,您可以通过注册/指示提供程序,将BouncyCastle实现用作基础提供程序。有趣的是,Bouncy Castle库现在有一个相当快的EC实现,它比Oracle提供的实现快,尽管它是在本机代码中实现的二进制输出与OpenSSL的签名输入直接兼容。要创建文本字符串,可以将字节数组编码为基64字符串(最好没有行尾,例如
Base64.encode(derEncodedsignature)
),然后必须由openssl enc -base64 -A -d -in signature.txt -out signatureToVerify.bin
解码