安卓工作室使用公钥验证椭圆p256签名时出现问题.ECDSA



我被这件事困扰了一段时间。我已经了解了如何从EC公钥字节中获取PublicKey对象?方法这对他的榜样有效,但对我的榜样无效。不确定哪里出了问题。该示例适用于node.js,但当使用ECC椭圆中的公钥、msg和签名时,它总是返回false。

byte[] pubKey = Hex.decode("04f491ccd1913757e10c2fe965ac764dd6af2f8bbfa47f4dddff0fe7736601701464d9fa02e6eada870ac626825e28d99bdf2d3a2742ba6dc99a56c663e875852a");
byte[] message = Hex.decode("613839633666323863616238633538623533313466626365636364326363633166646537643937383663373863373134313432646230343361313530323937657c416c6920416873616e7c43562d4d3957515253544d7c4d616c657c4d59537c323032312d30352d30355431303a33303a32392b30383a30307c3235383530303030317c39343735362d347c313234303538313030303030303130347c4b75616c61204c756d70757220486f73706974616c7c3031");
byte[] signature = Hex.decode("304502202f70fe9a8173a13daef97e8d59c9cd9aec3851c0f0568e5b5d61ddb752d1cb9e022100d9eccdcdd4b4a448bd36f3a9dafde08b55b8176f6b21bb6e1cc7d35a929dc1bf");

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);
System.out.println(getPublicKeyFromBytes(pubKey));
System.out.println(message);
System.out.println(signature);
return ecdsaVerify.verify(signature);
}
private static PublicKey getPublicKeyFromBytes(byte[] pubKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("P-256");
KeyFactory kf = KeyFactory.getInstance("ECDSA", new BouncyCastleProvider());
ECNamedCurveSpec params = new ECNamedCurveSpec("P-256", spec.getCurve(), spec.getG(), spec.getN());
ECPoint point =  ECPointUtil.decodePoint(params.getCurve(), pubKey);
ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(point, params);
ECPublicKey pk = (ECPublicKey) kf.generatePublic(pubKeySpec);
return pk;
}

如果有人能帮忙,我将不胜感激。热烈问候。


以下是在节点上创建的:

console.log("Create D. Signature: ");
let elliptic = require('elliptic');
let sha3 = require('js-sha3');
let ec = new elliptic.ec('p256');
let key = ec.keyFromPrivate("our private key");
let msgHash = sha3.sha3_256('scv1|Ali Ahsan|CV-M9WQRSTM|Male|MYS|2021-05- 05T10:30:29+08:00|258500001|94756-4|1240581000000104|Kuala Lumpur Hospital|01'); 
console.log("msgHash: "+msgHash);
let signature = key.sign(msgHash); signature=signature.toDER(); signature=Buffer.from(signature).toString('hex'); console.log("signature: "+signature);
let pubPoint = key.getPublic('hex'); console.log('public key: '+pubPoint);
/*
console.log("Verify D. Signature:");
const qrContent = 'a89c6f28cab8c58b5314fbceccd2ccc1fde7d9786c78c714142db043a150297e|Ali Ahsan|CV-M9WQRSTM|Male|MYS|2021-05-05T10:30:29+08:00|258500001|94756-4|1240581000000104|Kuala Lumpur Hospital|01|304502202f70fe9a8173a13daef97e8d59c9cd9aec3851c0f0568e5b5d61ddb752d1cb9e022100d9eccdcdd4b4a448bd36f3a9dafde08b55b8176f6b21bb6e1cc7d35a929dc1bf'
const pub = '4f491ccd1913757e10c2fe965ac764dd6af2f8bbfa47f4dddff0fe7736601701464d9fa02e6eada870ac626825e28d99bdf2d3a2742ba6dc99a56c663e875852a'
const EC = require('elliptic').ec;
let ec = new EC('p256');
const key = ec.keyFromPublic(pub,'hex');
const sigIndex = qrContent.lastIndexOf('|');
const data = qrContent.slice(0, sigIndex);
const sig = qrContent.slice(sigIndex + 1, qrContent.length); 
console.log(data);
console.log(sig);
console.log(key.verify(data, sig);*/

根据您添加的nodejs代码,您正在执行SHA-3-256(而不是SHA-256,它是SHA-2算法(,因此您的Java代码需要与之匹配。但是,您发布的nodejs签名代码使用的数据值与nodejsjava验证代码使用的值不同,这将永远无法工作。即使修复了这些问题,你发布的值仍然无法为我验证。然而,以下稍微简化和更正的代码版本(使用不同的任意键(确实可以按预期工作:

$ cat SO68392857.js
// SO68392857.js
let msg = 'a89c6f28cab8c58b5314fbceccd2ccc1fde7d9786c78c714142db043a150297e|Ali Ahsan|CV-M9WQRSTM|Male|MYS|2021-05-05T10:30:29+08:00|258500001|94756-4|1240581000000104|Kuala Lumpur Hospital|01|';
// msg corrected(?) in first field and timestamp
let elliptic = require('elliptic');
let sha3 = require('js-sha3');
let ec = new elliptic.ec('p256');
let key = ec.keyFromPrivate('000102030405060707090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f');
let msgHash = sha3.sha3_256(msg); console.log("msgHash: "+msgHash);
let signature = Buffer.from(key.sign(msgHash).toDER()).toString('hex'); console.log("signature: "+signature);
let pubPoint = key.getPublic('hex'); console.log('public key: '+pubPoint);
const k2 = ec.keyFromPublic(pubPoint,'hex');
console.log("verify="+k2.verify(msgHash,signature)); // verify needs hash not msg
$ nodejs SO68392857.js
msgHash: 3b1254cd6bc46bab86d36b9c45fad246f8e9cd71b48dd36f19831b15bbdf94a2
signature: 3046022100c901843a6d63f04d168cc961748dbd3e86fd9352e87a4e8d3bd2126ee78414620221008438128c52eadb04f80671e935acfc1b36605eccc1652818afd05ab53d6781b0
public key: 0462a5b3db60f01fbaab42721a46b07061b0509162fbfb1291098e20d804be4970e9ff7954b1b2b33e7a9812d6833052a56b2f8c8c699ce20b80d17af68ce8fa8c
verify=true
$ cat SO68392857.java
// SO68392857.java
import java.security.*;
import java.security.interfaces.*;
import java.security.spec.*;
import java.util.*;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.ECPointUtil;
import org.bouncycastle.jce.spec.ECNamedCurveSpec;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class SO68392857 {
public static void main (String[] args) throws Exception {
byte[] msg = "a89c6f28cab8c58b5314fbceccd2ccc1fde7d9786c78c714142db043a150297e|Ali Ahsan|CV-M9WQRSTM|Male|MYS|2021-05-05T10:30:29+08:00|258500001|94756-4|1240581000000104|Kuala Lumpur Hospital|01|".getBytes(); // ASCII safe
byte[] sig = fromhex("3046022100c901843a6d63f04d168cc961748dbd3e86fd9352e87a4e8d3bd2126ee78414620221008438128c52eadb04f80671e935acfc1b36605eccc1652818afd05ab53d6781b0");
byte[] pub = fromhex("0462a5b3db60f01fbaab42721a46b07061b0509162fbfb1291098e20d804be4970e9ff7954b1b2b33e7a9812d6833052a56b2f8c8c699ce20b80d17af68ce8fa8c");
Security.addProvider(new BouncyCastleProvider());
// getPublicKeyFromBytes
ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("P-256");
KeyFactory kf = KeyFactory.getInstance("ECDSA", "BC");
ECNamedCurveSpec params = new ECNamedCurveSpec("P-256", spec.getCurve(), spec.getG(), spec.getN());
ECPoint point =  ECPointUtil.decodePoint(params.getCurve(), pub);
ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(point, params);
ECPublicKey pk = (ECPublicKey) kf.generatePublic(pubKeySpec);
// isValidSignature
Signature ecdsaVerify = Signature.getInstance("SHA3-256withECDSA", "BC");
ecdsaVerify.initVerify(pk);
ecdsaVerify.update(msg);
System.out.println("verify="+ecdsaVerify.verify(sig));
// check that altering either data or signature is caught
byte[] badmsg = Arrays.copyOf(msg,msg.length); badmsg[badmsg.length-1] ^= 1;
ecdsaVerify.initVerify(pk);
ecdsaVerify.update(badmsg);
System.out.println("badmsg="+ecdsaVerify.verify(sig));
byte[] badsig = Arrays.copyOf(sig,sig.length); badsig[badsig.length-1] ^= 1;
ecdsaVerify.initVerify(pk);
ecdsaVerify.update(msg);
System.out.println("badsig="+ecdsaVerify.verify(badsig));
}
static byte[] fromhex(String x){
byte[] t = new byte[x.length()/2];
for(int i = 0; i<t.length; i++) t[i] = (byte) Integer.parseInt(x.substring(i*2,i*2+2),16);
return t;
}
}
$ java -cp [path_to_bouncy_jar] SO68392857.java # java can now run single-class without precompiling
verify=true
badmsg=false
badsig=false

所以你一定还是有什么不对劲的地方没有在你的帖子中显示出来。比较一下我做的有效的和你做的无效的。

我注意到你现在提到了安卓系统。我自己没有安卓系统,但据我所知,它有一个的bouncycastle(spongycastle(端口,而不是真的。可以想象这就是问题所在,尽管我希望如此广泛使用的东西不会出现这样的问题。但你可能会对照真正有弹性的桌面Java(至少1.55(

最新更新