我正在尝试编写Ruby代码来检查我在此处找到的特定消息上的椭圆曲线数字签名算法(ECDSA)签名.
问题是我不知道如何将公钥的八位字节串转换为OpenSSL :: PKey :: EC :: Point对象.如果我用C语言写这个,我只是将八位字节字符串传递给OpenSSL o2i_ECPublicKey,它做了一些接近我想要的东西,实际上是由参考实现使用的.但是,我搜索了Ruby(MRI)的源代码并且它不包含任何调用,o2i_ECPublicKey因此我不知道如何在不编写C扩展的情况下从Ruby中使用该函数.
这是十六进制的八位字符串.它只是一个0x04字节,后跟两个32字节整数,表示椭圆曲线上点的x和y坐标:
04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284
Run Code Online (Sandbox Code Playgroud)
那么有谁知道如何将该字符串转换为OpenSSL::PKey::EC::PointRuby 中的in?一旦我得到了点对象,我将在下面的代码中使用它,我认为这将验证签名:
key = OpenSSL::PKey::EC.new('secp256k1')
key.public_key = point
result = key.dsa_verify_asn1(digest, signature)
Run Code Online (Sandbox Code Playgroud)
更新:
感谢Jay-Ar Polidario,我得到了它的工作.以下是我使用OpenSSL验证签名的完整代码.我还写了一个名为ecdsa的宝石,我包含的代码显示了如何使用我的宝石做同样的事情.
# coding: ASCII-8BIT
digest =
"\xbf\x91\xfb\x0b\x4f\x63\x33\x77\x4a\x02\x2b\xd3\x07\x8e\xd6\xcc" \
"\xd1\x76\xee\x31\xed\x4f\xb3\xf9\xaf\xce\xb7\x2a\x37\xe7\x87\x86"
signature_der_string =
"\x30\x45" \
"\x02\x21\x00" \
"\x83\x89\xdf\x45\xf0\x70\x3f\x39\xec\x8c\x1c\xc4\x2c\x13\x81\x0f" \
"\xfc\xae\x14\x99\x5b\xb6\x48\x34\x02\x19\xe3\x53\xb6\x3b\x53\xeb" \
"\x02\x20" \
"\x09\xec\x65\xe1\xc1\xaa\xee\xc1\xfd\x33\x4c\x6b\x68\x4b\xde\x2b" \
"\x3f\x57\x30\x60\xd5\xb7\x0c\x3a\x46\x72\x33\x26\xe4\xe8\xa4\xf1"
public_key_octet_string =
"\x04" \
"\xfc\x97\x02\x84\x78\x40\xaa\xf1\x95\xde\x84\x42\xeb\xec\xed\xf5" \
"\xb0\x95\xcd\xbb\x9b\xc7\x16\xbd\xa9\x11\x09\x71\xb2\x8a\x49\xe0" \
"\xea\xd8\x56\x4f\xf0\xdb\x22\x20\x9e\x03\x74\x78\x2c\x09\x3b\xb8" \
"\x99\x69\x2d\x52\x4e\x9d\x6a\x69\x56\xe7\xc5\xec\xbc\xd6\x82\x84"
# Verifying with …Run Code Online (Sandbox Code Playgroud) 我已经测试了一个解决方案,以验证ECDSA签名(如何从EC公钥字节中获取PublicKey对象?),它与给定数据完美配合.
这是数据:
byte[] pubKey = DatatypeConverter.parseHexBinary("049a55ad1e210cd113457ccd3465b930c9e7ade5e760ef64b63142dad43a308ed08e2d85632e8ff0322d3c7fda14409eafdc4c5b8ee0882fe885c92e3789c36a7a");
byte[] message = DatatypeConverter.parseHexBinary("54686973206973206a75737420736f6d6520706f696e746c6573732064756d6d7920737472696e672e205468616e6b7320616e7977617920666f722074616b696e67207468652074696d6520746f206465636f6465206974203b2d29");
byte[] signature = DatatypeConverter.parseHexBinary("304402205fef461a4714a18a5ca6dce6d5ab8604f09f3899313a28ab430eb9860f8be9d602203c8d36446be85383af3f2e8630f40c4172543322b5e8973e03fff2309755e654");
Run Code Online (Sandbox Code Playgroud)
这是代码(打印为true):
private static boolean isValidSignature(byte[] pubKey, byte[] message,byte[] signature) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, SignatureException, InvalidKeySpecException {
Signature ecdsaVerify = Signature.getInstance("SHA256withECDSA", new BouncyCastleProvider());
ecdsaVerify.initVerify(getPublicKeyFromBytes(pubKey));
ecdsaVerify.update(message);
return ecdsaVerify.verify(signature);
}
private static PublicKey getPublicKeyFromBytes(byte[] pubKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("prime256v1");
KeyFactory kf = KeyFactory.getInstance("ECDSA", new BouncyCastleProvider());
ECNamedCurveSpec params = new ECNamedCurveSpec("prime256v1", spec.getCurve(), spec.getG(), spec.getN());
ECPoint point = ECPointUtil.decodePoint(params.getCurve(), pubKey);
ECPublicKeySpec pubKeySpec = …Run Code Online (Sandbox Code Playgroud) iOS 13的CryptoKit框架.rawRepresentation为ECDSA公钥和私钥提供了价值。我一直在尝试对rawRepresentation数据类型进行逆向工程,以便在它与JWK之间进行转换。从公钥表示形式的64字节长度来看,这似乎是一个简单的x || y串联。我猜想那会是私钥x || y || d,但是事实并非如此,因为这样做应该会产生96字节的字符串,而实际rawRepresentation是144字节。似乎也不是有效的DER / ASN.1字符串。我还没有找到符合我所得到的实际值的规格。
如您所料,Apple的文档具有很强的描述性。
rawRepresentation:私钥的表示形式,以字节的集合表示。
提供了十六进制的示例密钥对。
Private: 988f8187ff7f00007466815b0d6b02ae1a063198fd1e4923fb1e413195126cc00d30483284186b435726c0c69cc774274ea32eb6a17cbaf2ea88dd7f3a5a2a3ce637bc4b96523c2795035bd2fbeb093b010000000000000000000000000000000000000000000000000000000000000012b2b61abe8beae5aeb6d0bda739235364de96c7f498813cfb0336198dcf9063
Public: 2774c79cc6c02657436b18843248300dc06c129531411efb23491efd9831061a3b09ebfbd25b0395273c52964bbc37e63c2a5a3a7fdd88eaf2ba7ca1b62ea34e
Run Code Online (Sandbox Code Playgroud)
这是什么格式?
我试图从私钥生成公共 ECDSA 密钥,但我没有在互联网上找到太多关于如何执行此操作的帮助。几乎所有东西都是为了从公钥规范生成公钥,我不知道如何获得它。到目前为止,这是我整理的内容:
public void setPublic() throws GeneralSecurityException {
ECNamedCurveParameterSpec params = ECNamedCurveTable.getParameterSpec("secp256k1");
KeyFactory fact = KeyFactory.getInstance("ECDSA", "BC");
ECCurve curve = params.getCurve();
java.security.spec.EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, params.getSeed());
java.security.spec.ECPoint point = ECPointUtil.decodePoint(ellipticCurve, this.privateKey.getEncoded());
java.security.spec.ECParameterSpec params2=EC5Util.convertSpec(ellipticCurve, params);
java.security.spec.ECPublicKeySpec keySpec = new java.security.spec.ECPublicKeySpec(point,params2);
this.publicKey = fact.generatePublic(keySpec);
}
Run Code Online (Sandbox Code Playgroud)
但是,在运行时,我收到以下错误:
Exception in thread "main" java.lang.IllegalArgumentException: Invalid point encoding 0x30
at org.bouncycastle.math.ec.ECCurve.decodePoint(Unknown Source)
at org.bouncycastle.jce.ECPointUtil.decodePoint(Unknown Source)
at Wallet.Wallet.setPublic(Wallet.java:125)
Run Code Online (Sandbox Code Playgroud)
我究竟做错了什么?有没有更好/更简单的方法来做到这一点?
编辑:我已经设法编译了一些代码,但它不能正常工作:
public void setPublic() throws GeneralSecurityException {
BigInteger privKey = new BigInteger(getHex(privateKey.getEncoded()),16);
X9ECParameters ecp = SECNamedCurves.getByName("secp256k1");
ECPoint …Run Code Online (Sandbox Code Playgroud) 这不仅仅是一个问题,更是一个分享信息的帖子。
如果您通过 SSH 拉取私有存储库,则应该创建一个id_ecdsa,因为 Xcode 不接受 Ed25519 密钥,而是因为 github 从昨天起不再接受 RSA-SHA1。
https://github.blog/2021-09-01-improving-git-protocol-security-github/
要生成它,请使用:ssh-keygen -t ecdsa -C "your_email@example.com"
我有一些Go代码生成一个ECDSA密钥并将其写入文件:
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
ecder, err := x509.MarshalECPrivateKey(priv)
keypem, err := os.OpenFile("ec-key.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
pem.Encode(keypem, &pem.Block{Type: "EC PRIVATE KEY", Bytes: ecder})
Run Code Online (Sandbox Code Playgroud)
这适用于并生成"BEGIN EC PRIVATE KEY"块.但是当你在openssl中写出密钥时,你也会得到一个"BEGIN EC PARAMETERS"块,指定使用的曲线.有没有办法将EC参数写入Go中的pem文件?
目前,当我使用以下方法创建密钥时
private KeyPair getKeyPair() throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("ECDsA", "SC");
ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256k1");
keyGen.initialize(ecSpec, new SecureRandom());
return keyGen.generateKeyPair();
}
Run Code Online (Sandbox Code Playgroud)
KeyPairGenerator有另一种方法,我可以在其中指定keySize,但我不知道如何通过ecSpec.
public void initialize(int keysize, SecureRandom random)
Run Code Online (Sandbox Code Playgroud) 我有使用jsrsasignJKK格式的密钥为ECDSA签名生成连接(rs)签名的代码:
const sig = new Signature({ alg: 'SHA256withECDSA' });
sig.init(KEYUTIL.getKey(key));
sig.updateHex(dataBuffer.toString('hex'));
const asn1hexSig = sig.sign();
const concatSig = ECDSA.asn1SigToConcatSig(asn1hexSig);
return new Buffer(concatSig, 'hex');
Run Code Online (Sandbox Code Playgroud)
似乎工作.我也有SubtleCrypto用于实现同样的事情的代码:
importEcdsaKey(key, 'sign') // importKey JWK -> raw
.then((privateKey) => subtle.sign(
{ name: 'ECDSA', hash: {name: 'SHA-256'} },
privateKey,
dataBuffer
))
Run Code Online (Sandbox Code Playgroud)
这两个都返回128字节的缓冲区; 并且他们交叉验证(即我可以验证jsrsasign签名,SubtleCrypto反之亦然).但是,当我Sign在Node.js crypto模块中使用该类时,我似乎得到了一些完全不同的东西.
key = require('jwk-to-pem')(key, {'private': true});
const sign = require('crypto').createSign('sha256');
sign.update(dataBuffer);
return sign.sign(key);
Run Code Online (Sandbox Code Playgroud)
这里我得到一个可变长度的缓冲区,大约70个字节; 它没有交叉验证jsrsa(抱怨rs签名的长度无效).
我怎样才能得到一个RS签名,通过所产生jsrsasign和SubtleCrypto使用节点crypto …
我们可以使用RSA密钥创建XML数字签名.但是如何使用椭圆曲线键来签署xml文件?我收到错误消息,如 -
Exception in thread "main" java.security.KeyException: ECKeyValue not supported
at org.jcp.xml.dsig.internal.dom.DOMKeyValue$EC.<init>(DOMKeyValue.java:350)
at org.jcp.xml.dsig.internal.dom.DOMKeyInfoFactory.newKeyValue(DOMKeyInfoFactory.java:71)
at csr.ExtractEC.main(XMLSignatureECTest.java:57)
Caused by: java.lang.ClassNotFoundException: sun/security/ec/ECParameters
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at org.jcp.xml.dsig.internal.dom.DOMKeyValue$EC.getMethods(DOMKeyValue.java:367)
at org.jcp.xml.dsig.internal.dom.DOMKeyValue$EC$1.run(DOMKeyValue.java:343)
at org.jcp.xml.dsig.internal.dom.DOMKeyValue$EC$1.run(DOMKeyValue.java:339)
at java.security.AccessController.doPrivileged(Native Method)
at org.jcp.xml.dsig.internal.dom.DOMKeyValue$EC.<init>(DOMKeyValue.java:338)
... 2 more
Run Code Online (Sandbox Code Playgroud)
我用下面的代码创建了SignatureMethod和KeyInfo -
String url = "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256";
SignatureMethod signatureMethod = factory.newSignatureMethod(url, null);
SignedInfo signedInfo = factory.newSignedInfo(c14n, signatureMethod, Collections.singletonList(reference));
PrivateKey privateKey = Utils.generatePrivateEC("e:\\certs\\ec\\ec.key.p8");
Certificate certificate = Utils.generatePublic("e:\\certs\\ec\\ec.cer");
KeyInfoFactory keyInfoFactory = factory.getKeyInfoFactory();
KeyValue keyValue = keyInfoFactory.newKeyValue(certificate.getPublicKey());
KeyInfo keyInfo = keyInfoFactory.newKeyInfo(Collections.singletonList(keyValue));
Run Code Online (Sandbox Code Playgroud)
JDK - Oracle JDK …
I am wondering if this is a correct way to create PrivateKey object in Java from HEX string from this website: https://kjur.github.io/jsrsasign/sample/sample-ecdsa.html
Create a BigInteger from a HEX String:
BigInteger priv = new BigInteger(privateKeyFromSite, 16);
Run Code Online (Sandbox Code Playgroud)
And pass to this method:
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.spec.InvalidKeySpecException;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
public static PrivateKey getPrivateKeyFromECBigIntAndCurve(BigInteger s, String curveName) {
ECParameterSpec ecParameterSpec = ECNamedCurveTable.getParameterSpec(curveName);
ECPrivateKeySpec privateKeySpec = new ECPrivateKeySpec(s, ecParameterSpec);
try {
KeyFactory keyFactory = KeyFactory.getInstance(EC); …Run Code Online (Sandbox Code Playgroud) ecdsa ×10
java ×5
bouncycastle ×4
cryptography ×3
android ×1
binary-data ×1
encryption ×1
github ×1
go ×1
key-pair ×1
node.js ×1
openssl ×1
ruby ×1
signature ×1
ssh ×1
swift ×1
xcode ×1
xml-dsig ×1