Generate private-public key pair. Use the key pair to sign and verify message using ECDSA
Digital signatures are used to verify
Digital signature can be generated by any cryptographic hash function. Let's say SHA256.
The author sends both public key and the signature with the document. java.security package contains ECDSA classes for generating key pair, signing and verifying signatures. There are other third-party libraries like Bouncy Castle. But for this example, we will use the standard libraries provided since Java 7.
Elliptic curve with Digital Signature Algorithm (ECDSA) is designed for digital signatures. This algorithm generates a private-public key pair. The keys can be reused. So this code can be called once and we use the pair values for sending and receiving.
ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256k1");
KeyPairGenerator g = KeyPairGenerator.getInstance("EC");
g.initialize(ecSpec, new SecureRandom());
KeyPair keypair = g.generateKeyPair();
PublicKey publicKey = keypair.getPublic();
PrivateKey privateKey = keypair.getPrivate();
The sender signs the message with private key and sends
to the receiver.
//at sender's end
Signature ecdsaSign = Signature.getInstance("SHA256withECDSA");
ecdsaSign.initSign(privateKey);
ecdsaSign.update(plaintext.getBytes("UTF-8"));
byte[] signature = ecdsaSign.sign();
String pub = Base64.getEncoder().encodeToString(publicKey.getEncoded());
String sig = Base64.getEncoder().encodeToString(signature);
The same algorithm needs to be used on the client as well, to verify the message. So it's better the sender also sends the algorithm used for signing. In our case it's
SHA256withECDSA
The sender will send his public key with the message. Here we wont convert the Bytes to Bitcoin address format, but to Base64 encoding.
Let's say the receiver gets a json object over the network.
{
"publicKey": "MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEMEV3EPREEDc0t4MPeuYgreLMHMVfD7iYJ2Cnkd0ucwf3GYVySvYTttMVMNMEKF554NYmdrOlqwo2s8J2tKt/oQ==",
"message": "Hello",
"signature": "MEUCIQCsuI4OcBAyA163kiWji1lb7xAtC8S0znf62EpdA+U4zQIgBcLbXtcuxXHcwQ9/DmiVfoiigKnefeYgpVXZzjIuYn8=",
"algorithm": "SHA256withECDSA"
}
The following code can verify the signature using the data in the message.
JSONObject obj = ...;
// at receiver's end
Signature ecdsaVerify = Signature.getInstance(obj.getString("algorithm"));
KeyFactory kf = KeyFactory.getInstance("EC");
EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(obj.getString("publicKey")));
KeyFactory keyFactory = KeyFactory.getInstance("EC");
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
ecdsaVerify.initVerify(publicKey);
ecdsaVerify.update(obj.getString("message").getBytes("UTF-8"));
boolean result = ecdsaVerify.verify(Base64.getDecoder().decode(obj.getString("signature")));
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.EncodedKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.json.JSONObject;
/**
*
* @author metamug.com
*/
public class DigiSig {
private static final String SPEC = "secp256k1";
private static final String ALGO = "SHA256withECDSA";
private JSONObject sender() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, UnsupportedEncodingException, SignatureException {
ECGenParameterSpec ecSpec = new ECGenParameterSpec(SPEC);
KeyPairGenerator g = KeyPairGenerator.getInstance("EC");
g.initialize(ecSpec, new SecureRandom());
KeyPair keypair = g.generateKeyPair();
PublicKey publicKey = keypair.getPublic();
PrivateKey privateKey = keypair.getPrivate();
String plaintext = "Hello";
//...... sign
Signature ecdsaSign = Signature.getInstance(ALGO);
ecdsaSign.initSign(privateKey);
ecdsaSign.update(plaintext.getBytes("UTF-8"));
byte[] signature = ecdsaSign.sign();
String pub = Base64.getEncoder().encodeToString(publicKey.getEncoded());
String sig = Base64.getEncoder().encodeToString(signature);
System.out.println(sig);
System.out.println(pub);
JSONObject obj = new JSONObject();
obj.put("publicKey", pub);
obj.put("signature", sig);
obj.put("message", plaintext);
obj.put("algorithm", ALGO);
return obj;
}
private boolean receiver(JSONObject obj) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, UnsupportedEncodingException, SignatureException {
Signature ecdsaVerify = Signature.getInstance(obj.getString("algorithm"));
KeyFactory kf = KeyFactory.getInstance("EC");
EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(obj.getString("publicKey")));
KeyFactory keyFactory = KeyFactory.getInstance("EC");
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
ecdsaVerify.initVerify(publicKey);
ecdsaVerify.update(obj.getString("message").getBytes("UTF-8"));
boolean result = ecdsaVerify.verify(Base64.getDecoder().decode(obj.getString("signature")));
return result;
}
public static void main(String[] args){
try {
DigiSig digiSig = new DigiSig();
JSONObject obj = digiSig.sender();
boolean result = digiSig.receiver(obj);
System.out.println(result);
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(DigiSig.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvalidAlgorithmParameterException ex) {
Logger.getLogger(DigiSig.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvalidKeyException ex) {
Logger.getLogger(DigiSig.class.getName()).log(Level.SEVERE, null, ex);
} catch (UnsupportedEncodingException ex) {
Logger.getLogger(DigiSig.class.getName()).log(Level.SEVERE, null, ex);
} catch (SignatureException ex) {
Logger.getLogger(DigiSig.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvalidKeySpecException ex) {
Logger.getLogger(DigiSig.class.getName()).log(Level.SEVERE, null, ex);
}
}
}