首页 > 解决方案 > 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();
                }
            }
        });

问题是,每次在上面的代码中验证签名时,它可以随机返回真或假,即使发送消息的用户是同一用户......所以问题是:

  1. 为什么结果总是随机的,即使它是由同一个用户发送的?
  2. 我如何使它同意始终返回 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

好的,所以我怀疑我的曲线操作有问题,您可以在此处访问

我测试了从这里到我的应用程序的点操作代码,它运行得很好.. 几乎没有不一致,所以问题的原因在于我上面链接的点操作代码......

所以我的更新问题是,我的点操作代码中的哪个部分是错误的?

标签: javadigital-signatureecdsa

解决方案


推荐阅读