java - Java:ECDSA 签名验证返回不一致的结果
问题描述
注意:我曾尝试使用“ECDSA 验证”搜索一侧,但发布的问题是使用包或框架中的服务,而不是纯粹的实现,这就是我提出这个问题的原因
所以,基本上,我想在每次发送消息时都签名......我如何发送和签名的代码如下,
发信息
send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String messageContent = typeMessage.getText().toString();
String Sign = new String();
final BigInteger dA = BigInteger.probablePrime(192,new Random());
ecdsa.setdA(dA);
Point QA = new Point();
QA = ecdsa.getQA();
Sign = ecdsa.SignMessage(messageContent);
if((!messageContent.equals("")) && (ecdsa.MessageVerify(messageContent,Sign))){
Map<String,String> messageTextBody = new HashMap<String,String>();
messageTextBody.put("Message",messageContent);
messageTextBody.put("User", Username);
messageTextBody.put("Signature", Sign);
reference1.push().setValue(messageTextBody);
reference2.push().setValue(messageTextBody);
typeMessage.setText("");
}else{
Toast.makeText(getApplicationContext(),"You are not the sender",Toast.LENGTH_SHORT).show();
}
}
});
问题是,每次在上面的代码中验证签名时,它可以随机返回真或假,即使发送消息的用户是同一用户......所以问题是:
- 为什么结果总是随机的,即使它是由同一个用户发送的?
- 我如何使它同意始终返回 true,因为发送它的用户本质上是同一用户?
下面我发布了有关签名生成和签名验证的代码以获取更多信息
签名生成
//Signing Message
public String SignMessage(String message){
Point sign = SignGeneration(message);
String signString = sign.toHexString();
return signString;
}
//Generate Signature
private Point SignGeneration(String message){
BigInteger k = BigInteger.ZERO;
BigInteger hash = BigInteger.ZERO;
BigInteger r = BigInteger.ZERO;
BigInteger s = BigInteger.ZERO;
Random random = new Random(); //variabel for random k
Point xy = new Point(); //variabel for kG
String H = generateSha1String(message);
hash = new BigInteger(H,16); //Compute hash
//Proses
do{
k = randomBigInt(n.subtract(BigInteger.ONE)); //Generate random bigint with max range n-1
xy = G.multiplication(k); //do k*G
r = xy.getX().mod(n); //Compute r by get x_1 fro xy and mod it with n
if(!(r.compareTo(BigInteger.ZERO) == 0) ){
if(k.gcd(n).compareTo(BigInteger.ONE) == 0){
BigInteger temp = k.modInverse(n);
s = (temp.multiply((dA.multiply(r))).add(hash)).mod(n); //Compute s
}
}
}while((r.compareTo(BigInteger.ZERO) == 0) || (s.compareTo(BigInteger.ZERO) == 0));
Point sign = new Point();
sign.setX(r); //Set x value as r
sign.setY(s); //Set y value as s
return sign;
}
签名验证
//Verify Message Signature
public boolean MessageVerify(String message, String sign){
int length = sign.length();
Point Signature = new Point();
Signature.setX(new BigInteger(sign.substring(0, length/2), 16));
Signature.setY(new BigInteger(sign.substring(length/2), 16));
return SignVerification(message, Signature);
}
//Signature Verification
private boolean SignVerification(String message, Point sign){
//Verify r and s random integer in range max n-1
BigInteger r = sign.getX();
BigInteger s = sign.getY();
BigInteger w,u1,u2 = BigInteger.ZERO;
if(((r.compareTo(BigInteger.ONE) >= 0) && (r.compareTo(n.subtract(BigInteger.ONE)) <= 0)) && ((s.compareTo(BigInteger.ONE) >= 0) && (s.compareTo(n.subtract(BigInteger.ONE)) <= 0))){
String H = generateSha1String(message);
BigInteger e = new BigInteger(H,16); //Compute e
w = s.modInverse(n); //Compute w
u1 = (e.multiply(w)).mod(n); //Compute u1
u2 = (r.multiply(w)).mod(n); //Compute u2
Point X = new Point();
X = (G.multiplication(u1)).addition(QA.multiplication(u2));//Compute X
Log.d("n", n.toString());
if((X.getX().mod(n)).compareTo(r.mod(n)) == 0){
return true;
}else{
return false;
}
}else{
return false;
}
}
进步
由于问题出现在验证过程中,我尝试在 MessageVerify中记录值
我使用 Log.d 记录了消息、符号、setX 和 SetY 值,如下所示:
Log.d("Message", message);
Log.d("sign", sign);
Log.d("setX", new BigInteger(sign.substring(0, length/2), 16).toString());
Log.d("setY", new BigInteger(sign.substring(length/2), 16).toString());
验证成功的结果是:
Message:test
Signature:188da80eb03090f67cbf20eb43a18800f4ff0afd82ff10127aa1eed4767a2a901f168332709baf22fc29f202527a2059
SetX:602046282375688656758213480587526111916698976636884684818
SetY:3006941389036669779186569967069188912278324616389591703641
验证失败的结果是:
Message:test
Signature: 188da80eb03090f67cbf20eb43a18800f4ff0afd82ff10126ed05452fa30cf258551fde4bc9453f7ed4fe08aa38e78d6
SetX:602046282375688656758213480587526111916698976636884684818
SetY:2717146143357900544226079474350104288116509888386597550294
即使我仍然不知道问题来自哪里,但上面的测试表明问题可能来自签名生成过程......但这仍然不确定
更新 2 我正在测试其他人这里的源代码 他们的标志生成源是这样的
private Point signatureGeneration(String m){
BigInteger e, k, r, s = BigInteger.ZERO;
// e = HASH(m)
e = new BigInteger("7e16b5527c77ea58bac36dddda6f5b444f32e81b", 16);
Point x1y1 = new Point();
Random rand = new Random();
do{
k = randomBigInteger(n.subtract(BigInteger.ONE));
x1y1 = G.multiplication(k);
r = x1y1.getX().mod(n);
if (! (r.compareTo(BigInteger.ZERO) == 0)){
if (k.gcd(n).compareTo(BigInteger.ONE) == 0){
BigInteger temp = k.modInverse(n);
s = (temp.multiply((dA.multiply(r)).add(e))).mod(n);
}
}
} while ((r.compareTo(BigInteger.ZERO) == 0) || (s.compareTo(BigInteger.ZERO) == 0));
Point signature = new Point();
signature.setX(r);
signature.setY(s);
return signature;
}
他们的验证过程是这样的
private boolean signatureVerification(String m, Point signature){
BigInteger r = signature.getX();
BigInteger s = signature.getY();
BigInteger e, w, u1, u2;
if ((r.compareTo(BigInteger.ONE) >= 0) &&
(r.compareTo(n.subtract(BigInteger.ONE)) <= 0) &&
(s.compareTo(BigInteger.ONE) >= 0) &&
(s.compareTo(n.subtract(BigInteger.ONE)) <= 0)){
// e = HASH(m)
e = new BigInteger("7e16b5527c77ea58bac36dddda6f5b444f32e81b", 16);
w = s.modInverse(n);
u1 = (e.multiply(w)).mod(n);
u2 = (r.multiply(w)).mod(n);
Point x1y1 = new Point();
x1y1 = (G.multiplication(u1)).addition(QA.multiplication(u2));
if ((x1y1.getX().mod(n)).compareTo(r.mod(n)) == 0){
return true;
} else {
System.out.println("x1 = " + x1y1.getX().mod(n) + " | " + "r(mod n) = " + r.mod(n));
return false;
}
} else {
return false;
}
}
不幸的是,结果仍然相同......不一致
更新 3
有人建议在线测试向量并将我得到的结果与实际结果进行比较.. 还有人说要检查返回失败验证的 dA 值,将在测试向量后更新...
我忘了提到我使用的标准是 P-192,但目前的标准是从这里开始使用 P-256
更新 4
我测试了返回 true 和 false 的 dA(私钥)
返回 true 的几个 dA
4932586797028446313791604162219331331880743384320484031523
4995058672683066518736860284447908987220060049995439736509
5862956776220859815493689331273390248765373547354939967957
6201324543883668844361639115428609811595727287245749002217
5222838399154712950243036378095036772903676114969495577797
返回 false 的几个 dA
5425881164364981298041514040021735320995877440649227863027
5470323348832879969905327607374162405372818407344053932703
4946291572348807919810717095782002153268269929161598490177
4769474209716033018356422804849914975531275486757124133339
5134885695167195771629094047829365443294217726343663308709
更新 5
好的,所以我怀疑我的曲线操作有问题,您可以在此处访问
我测试了从这里到我的应用程序的点操作代码,它运行得很好.. 几乎没有不一致,所以问题的原因在于我上面链接的点操作代码......
所以我的更新问题是,我的点操作代码中的哪个部分是错误的?
解决方案
推荐阅读
- windows - 找到超过 2 个 binskim 的 exe,恐慌!在 MobSF
- c - C、不带空格或制表符的字符串输入
- python - 字典和相似键的字典,只有字典理解
- android - 版本冲突(google-services 插件)
- javascript - 找到一个 html 元素
- apache-kafka - Kinesis 如何实现 Kafka 风格的 Consumer Groups?
- php - 如何从 MySQL 获取过去 7 天的行?
- aws-lambda - 无法导入模块“src/index”:Function.Module._load (module.js:438:3) 出错
- javascript - Get javascript values from calculation and insert them into mysql database
- php - Is it possible to treat $_POST like single quotes rather the double quotes?