如何验证由 ECDSA [r, s] 值组成的 openssl 中的签名?
How to verify a signature in openssl consisting of ECDSA [r, s] values?
我正在使用 Bouncy Castle/Java 生成签名,因为它给出了 2 个具有 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"
,运行 上面的实用程序 returns 我是带分隔符 '|' 的 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 端不断收到 "Verification Failure" 错误。
OpenSSL 需要 X9.62 签名。这由两个整数值 R 和 S 的 DER 编码组成。如果您查看提供商 class SignatureSpi
的 Bouncy Castle 源代码,您会发现:
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(new ASN1Integer(r));
v.add(new ASN1Integer(s));
byte[] derEncodedSignature = new DERSequence(v).getEncoded(ASN1Encoding.DER);
您应该使用 Bouncy Castle 对签名进行编码。这里 r
和 s
应该是您在二元结果数组中得到的 BigInteger
值。
您可能已经猜到了,您也可以改用 Java JCA Signature
class,这将产生相同的签名编码。如果需要或想要,您可以通过注册/指示提供者来使用 BouncyCastle 实现作为基础提供者。有趣的是,Bouncy Castle 库现在有一个非常快的 EC 实现,它击败了 Oracle 提供的实现,即使它是在本机代码中。
binary 输出与 OpenSSL 的签名输入直接兼容。要创建文本字符串,可以将字节数组编码为 base 64 字符串(最好没有行尾,例如 Base64.encode(derEncodedsignature)
),然后必须通过 openssl enc -base64 -A -d -in signature.txt -out signatureToVerify.bin
对其进行解码
我正在使用 Bouncy Castle/Java 生成签名,因为它给出了 2 个具有 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"
,运行 上面的实用程序 returns 我是带分隔符 '|' 的 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 端不断收到 "Verification Failure" 错误。
OpenSSL 需要 X9.62 签名。这由两个整数值 R 和 S 的 DER 编码组成。如果您查看提供商 class SignatureSpi
的 Bouncy Castle 源代码,您会发现:
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(new ASN1Integer(r));
v.add(new ASN1Integer(s));
byte[] derEncodedSignature = new DERSequence(v).getEncoded(ASN1Encoding.DER);
您应该使用 Bouncy Castle 对签名进行编码。这里 r
和 s
应该是您在二元结果数组中得到的 BigInteger
值。
您可能已经猜到了,您也可以改用 Java JCA Signature
class,这将产生相同的签名编码。如果需要或想要,您可以通过注册/指示提供者来使用 BouncyCastle 实现作为基础提供者。有趣的是,Bouncy Castle 库现在有一个非常快的 EC 实现,它击败了 Oracle 提供的实现,即使它是在本机代码中。
binary 输出与 OpenSSL 的签名输入直接兼容。要创建文本字符串,可以将字节数组编码为 base 64 字符串(最好没有行尾,例如 Base64.encode(derEncodedsignature)
),然后必须通过 openssl enc -base64 -A -d -in signature.txt -out signatureToVerify.bin