Tutorial of ECDSA algorithm to sign a string
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);
}
user1379574
Updated on July 05, 2022Comments
-
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 almost 12 yearsWhat curve would that be? P-256?
-
President James K. Polk almost 12 yearsI was afraid someone would ask that. I don't know, P-256 would be my guess though.
-
President James K. Polk almost 12 yearsRunning it in the debugger and cheating a little reveals: secp256r1 [NIST P-256, X9.62 prime256v1]
-
Maarten Bodewes almost 12 yearsOh, I just cast it to the ECPrivateKey and got the curve :) I like to explicitly name the curve though.
-
user1379574 almost 12 yearsthanks a lot for analysis. I will try and write a bit later=)
-
Jumbogram almost 12 years@GregS you know the dangers of calling String.getBytes() without an explicit character set...
-
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 almost 12 yearsDoes 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 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 over 9 yearsI 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 over 5 years@MaartenBodewes
System.err.println("Public Key: " + pub.toString());
shows Public Key: Sun EC public key, 256 bits public x coord: 19501778814434347530334294264752414149486648444804770040426369360038920483177 public y coord: 114925210518466507390625110183293395999411704799479237295270124024949219180290 parameters: secp256r1 [NIST P-256, X9.62 prime256v1] (1.2.840.10045.3.1.7) -
Vlad Markushin over 5 yearsWhat is
ECCCipher
? -
linehrr over 5 years@VladMarkushin it's just a class I named, ECC : Elliptic Curve Cryptography.
-
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.