使用secp256r1曲线和SHA256算法生成ECDSA签名 - BouncyCastle

时间:2014-08-12 10:18:31

标签: java bouncycastle sha256 ecdsa

我正在尝试使用带有secp256r1曲线(P256)的ECDSA和用于消息散列的SHA256算法生成签名。我也在使用Bouncy Castle图书馆。 代码如下,

public class MyTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
        new MyTest().getSign();
    }

    void getSign() {
        // Get the instance of the Key Generator with "EC" algorithm

        try {
            KeyPairGenerator g = KeyPairGenerator.getInstance("EC");
            ECGenParameterSpec kpgparams = new ECGenParameterSpec("secp256r1");
            g.initialize(kpgparams);

            KeyPair pair = g.generateKeyPair();
            // Instance of signature class with SHA256withECDSA algorithm
            Signature ecdsaSign = Signature.getInstance("SHA256withECDSA");
            ecdsaSign.initSign(pair.getPrivate());

            System.out.println("Private Keys is::" + pair.getPrivate());
            System.out.println("Public Keys is::" + pair.getPublic());

            String msg = "text ecdsa with sha256";//getSHA256(msg)
            ecdsaSign.update((msg + pair.getPrivate().toString())
                    .getBytes("UTF-8"));

            byte[] signature = ecdsaSign.sign();
            System.out.println("Signature is::"
                    + new BigInteger(1, signature).toString(16));

            // Validation
            ecdsaSign.initVerify(pair.getPublic());
            ecdsaSign.update(signature);
            if (ecdsaSign.verify(signature))
                System.out.println("valid");
            else
                System.out.println("invalid!!!!");

        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }

    }

}

这里使用KeyPair生成密钥对,但是根据我的要求,我将使用静态privateKey和公钥。此外,签名验证始终返回false。

需要帮助,我如何拥有静态私钥和验证部分。

2 个答案:

答案 0 :(得分:7)

累积奖金 - 你头衔中没有任何问题!

首先,您可能实际上并未使用BouncyCastle。 Sun / Oracle Java 7和8现在包括EC提供程序(早期版本没有),而{arg形式的getInstance使用第一个可用的提供程序,通常是SunEC,除非您或某人更改了提供程序列表。

验证签名:在您转到签名Signature.update()时,将相同的数据传递给验证Signature.update()完全相同的字节字节。将签名值传递给Signature.verify()。将PrivateKey.toString()放入数据中是愚蠢的;此值特定于正在运行的Java进程,因此您必须将其发送到接收进程(如果它通常应该是不同的),它将无用且浪费空间。

使用静态密钥:这样做。创建一个密钥对并将其存储在某个地方,然后将其读入并使用它。最简单的安全(密码保护)存储是一个Java KeyStore(JKS)文件,但这需要一个证书链(可能是一个虚拟链),这对你自己编码很麻烦;幸运的是,带有keytool的{​​{1}}实用程序会生成带有虚拟自签名证书的密钥对,对于-genkeypair,它会使用(非常流行的)secp256r1曲线。同时指定您选择的-keyalg ec -keysize 256-alias name,虚拟证书的任何名称和密码。要使用JKS文件中的密钥对:

  • 使用-keystore filename创建商店对象,并在文件和密码上传递java.security.KeyStore.getInstance("JKS") .load(InputStream,char[])

  • 使用FileInputStream并强制转换以获取PrivateKey。用于签名。

  • 使用.getKey(String alias,char[] password)从第一个(唯一)证书中获取PublicKey。用于验证。

答案 1 :(得分:0)

我决定用最终的工作版本更新初始问题的代码,以供将来的读者使用。

    try {
        KeyPairGenerator kg = KeyPairGenerator.getInstance("EC");
        ECGenParameterSpec kpgparams = new ECGenParameterSpec("secp256r1");
        kg.initialize(kpgparams);

        KeyPair kp = kg.generateKeyPair();
        PublicKey pubKey = kp.getPublic();
        PrivateKey pvtKey = kp.getPrivate();

        // sign
        Signature ecdsaSign = Signature.getInstance("SHA256withECDSA");
        ecdsaSign.initSign(pvtKey);
        String message = "text ecdsa with sha256";//getSHA256(msg)
        ecdsaSign.update(message.getBytes(StandardCharsets.UTF_8), 0, message.length());
        byte[] signature = ecdsaSign.sign();

        // Validation
        ecdsaSign.initVerify(pubKey);
        ecdsaSign.update(message.getBytes(StandardCharsets.UTF_8), 0, message.length());
        boolean result = ecdsaSign.verify(signature);

        assertTrue(result); // junit5 assert
    } catch (Exception e) {
         e.printStackTrace();
    }