Tutorial of ECDSA algorithm to sign a string

42,360

Solution 1

Here is small example based on your example.

NOTE: this is the original code for this answer, please see the next code snippet for an updated version.

import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;

public class ECDSAExample {

    public static void main(String[] args) throws Exception {
        /*
         * Generate an ECDSA signature
         */

        /*
         * Generate a key pair
         */

        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
        SecureRandom random = SecureRandom.getInstance("SHA1PRNG");

        keyGen.initialize(256, random);

        KeyPair pair = keyGen.generateKeyPair();
        PrivateKey priv = pair.getPrivate();
        PublicKey pub = pair.getPublic();

        /*
         * Create a Signature object and initialize it with the private key
         */

        Signature dsa = Signature.getInstance("SHA1withECDSA");

        dsa.initSign(priv);

        String str = "This is string to sign";
        byte[] strByte = str.getBytes("UTF-8");
        dsa.update(strByte);

        /*
         * Now that all the data to be signed has been read in, generate a
         * signature for it
         */

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

    }
}

UPDATE: Here is slightly improved example removing deprecated algorithms. It also explicitly requests the NIST P-256 curve using the SECG notation "secp256r1" as specified in RFC 8422.

import java.math.BigInteger;
import java.security.*;
import java.security.spec.ECGenParameterSpec;

public class ECDSAExample {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws Exception {
        /*
         * Generate an ECDSA signature
         */

        /*
         * Generate a key pair
         */

        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");

        keyGen.initialize(new ECGenParameterSpec("secp256r1"), new SecureRandom());

        KeyPair pair = keyGen.generateKeyPair();
        PrivateKey priv = pair.getPrivate();
        PublicKey pub = pair.getPublic();

        /*
         * Create a Signature object and initialize it with the private key
         */

        Signature ecdsa = Signature.getInstance("SHA256withECDSA");

        ecdsa.initSign(priv);

        String str = "This is string to sign";
        byte[] strByte = str.getBytes("UTF-8");
        ecdsa.update(strByte);

        /*
         * Now that all the data to be signed has been read in, generate a
         * signature for it
         */

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

    }
}

Solution 2

class ECCCipher {
    @Override
    public byte[] sign(PrivateKey privateKey, String message) throws Exception {
        Signature signature = Signature.getInstance("SHA1withECDSA");
        signature.initSign(privateKey);

        signature.update(message.getBytes());

        return signature.sign();
    }

    @Override
    public boolean verify(PublicKey publicKey, byte[] signed, String message) throws Exception {
        Signature signature = Signature.getInstance("SHA1withECDSA");
        signature.initVerify(publicKey);

        signature.update(message.getBytes());

        return signature.verify(signed);
    }
}

========================

public class ECCCipherTest {

private final KeyPairGenerator keygen;

public ECCCipherTest() throws NoSuchProviderException, NoSuchAlgorithmException, InvalidAlgorithmParameterException {
    Security.addProvider(new BouncyCastleProvider());
    this.keygen = KeyPairGenerator.getInstance("ECDSA", "BC");
    keygen.initialize(new ECGenParameterSpec("brainpoolP384r1"));
}

@Test
public void ECC_CipherTest_1() throws Exception {
    String message = "hello world";

    ICipher<PrivateKey, PublicKey> cipher = new ECCCipher();
    KeyPair keyPair = keygen.generateKeyPair();

    byte[] encrypted = cipher.sign(keyPair.getPrivate(), message);

    Assert.assertTrue(cipher.verify(keyPair.getPublic(), encrypted, message));
}

}

this is a small code snippet from my project. it works for me. I have included one junit test as well; hopefully this helps.

just in case anyone wonders how we load the private key and pubkey: (note: privKey is the byte array representing the BigInteger in java, and the pubKey is the curve point in binary format)

    @Override
public PrivateKey generatePrivateKey(byte[] keyBin) throws InvalidKeySpecException, NoSuchAlgorithmException {
    ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("secp256k1");
    KeyFactory kf = KeyFactory.getInstance("ECDSA", new BouncyCastleProvider());
    ECNamedCurveSpec params = new ECNamedCurveSpec("secp256k1", spec.getCurve(), spec.getG(), spec.getN());
    ECPrivateKeySpec privKeySpec = new ECPrivateKeySpec(new BigInteger(keyBin), params);
    return kf.generatePrivate(privKeySpec);
}

@Override
public PublicKey generatePublicKey(byte[] keyBin) throws InvalidKeySpecException, NoSuchAlgorithmException {
    ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("secp256k1");
    KeyFactory kf = KeyFactory.getInstance("ECDSA", new BouncyCastleProvider());
    ECNamedCurveSpec params = new ECNamedCurveSpec("secp256k1", spec.getCurve(), spec.getG(), spec.getN());
    ECPoint point =  ECPointUtil.decodePoint(params.getCurve(), keyBin);
    ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(point, params);
    return kf.generatePublic(pubKeySpec);
}
Share:
42,360
user1379574
Author by

user1379574

Updated on July 05, 2022

Comments

  • user1379574
    user1379574 almost 2 years

    Can you help me to find a simple tutorial of how sign a string using ECDSA algorithm in java. But without using any third-party libraries like bouncycastle. Just JDK 7. I found it difficult to search a simple example, I'm new to cryptography.


    import java.io.*;
    import java.security.*;
    
    public class GenSig {
    
        /**
         * @param args the command line arguments
         */
        public static void main(String[] args) {
            /*
             * Generate a DSA signature
             */
    
            try {
    
                /*
                 * Generate a key pair
                 */
    
                KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA", "SUN");
                SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
    
                keyGen.initialize(1024, random);
    
                KeyPair pair = keyGen.generateKeyPair();
                PrivateKey priv = pair.getPrivate();
                PublicKey pub = pair.getPublic();
    
                /*
                 * Create a Signature object and initialize it with the private key
                 */
    
                Signature dsa = Signature.getInstance("SHA1withDSA", "SUN");
    
                dsa.initSign(priv);
    
                String str = "This is string to sign";
                byte[] strByte = str.getBytes();
                dsa.update(strByte);
    
                /*
                 * Now that all the data to be signed has been read in, generate a
                 * signature for it
                 */
    
                byte[] realSig = dsa.sign();
                System.out.println("Signature: " + new String(realSig));
    
    
            } catch (Exception e) {
                System.err.println("Caught exception " + e.toString());
            }
        }
    }
    

    How to modify it for ECDSA?

  • Maarten Bodewes
    Maarten Bodewes almost 12 years
    What curve would that be? P-256?
  • President James K. Polk
    President James K. Polk almost 12 years
    I was afraid someone would ask that. I don't know, P-256 would be my guess though.
  • President James K. Polk
    President James K. Polk almost 12 years
    Running it in the debugger and cheating a little reveals: secp256r1 [NIST P-256, X9.62 prime256v1]
  • Maarten Bodewes
    Maarten Bodewes almost 12 years
    Oh, I just cast it to the ECPrivateKey and got the curve :) I like to explicitly name the curve though.
  • user1379574
    user1379574 almost 12 years
    thanks a lot for analysis. I will try and write a bit later=)
  • Jumbogram
    Jumbogram almost 12 years
    @GregS you know the dangers of calling String.getBytes() without an explicit character set...
  • President James K. Polk
    President James K. Polk almost 12 years
    @Jumbogram I just did a copy and paste of the OPs example and missed it. Fixed now.
  • CodesInChaos
    CodesInChaos almost 12 years
    Does it support SHA-256 too? The security margin of SHA-1 against collisions is a bit on the low side, so I'd recommend SHA-256 where possible. P256 on the other hand is a fine curve, so no complaints about that part.
  • President James K. Polk
    President James K. Polk almost 12 years
    @CodeInChaos: It does. I didn't actually verify the signatures, but the example runs if you use instead Signature dsa = Signature.getInstance("SHA256withECDSA"); or any of the SHA2 algorithms in place of SHA256.
  • sparticvs
    sparticvs over 9 years
    I do want to thank you for this answer. I have been banging my head on a problem for the past several hours with using ECDSA and then the keystore camplaining that the algorithms dont match...Now it works, just wanted to share my gratitude.
  • Akintayo Olusegun
    Akintayo Olusegun over 5 years
    @MaartenBodewes System.err.println("Public Key: " + pub.toString()); shows Public Key: Sun EC public key, 256 bits public x coord: 195017788144343475303342942647524141494866484448047700404263‌​69360038920483177 public y coord: 114925210518466507390625110183293395999411704799479237295270‌​124024949219180290 parameters: secp256r1 [NIST P-256, X9.62 prime256v1] (1.2.840.10045.3.1.7)
  • Vlad Markushin
    Vlad Markushin over 5 years
    What is ECCCipher?
  • linehrr
    linehrr over 5 years
    @VladMarkushin it's just a class I named, ECC : Elliptic Curve Cryptography.
  • linehrr
    linehrr over 5 years
    @VladMarkushin oh it's actually the first block of the code. ok I added the class name there, so now you can see.