How can I compress or encode the public key of an elliptic curve and transmit it over the network?

I am developing a distributed digital signature that signs a document and sends it over the network to the application server. I am using socket programming in java for this. I think that the public key should be encoded or compressed ie the values ​​of x and y are somehow represented as single binary data and stored in a common registry or network. But I do not know how to do this in java.

// I have class like this public class CryptoSystem{ EllipticCurve ec = new EllipticCurve(new P192()); //------------------- //-------------------- public ECKeyPair generatekeyPair() { return ECKeyPair(ec); } } // i don't think i have problem in the above CryptoSystem crypto = new CryptoSystem(); ECKeyPair keyPair = crypto.generateKeyPair(); BigInteger prvKey = keyPair.getPrivateKey(); ECPoint pubKey = keyPair.getPublicKey(); // recommend me here to compress and send it the public key to a shared network. 

I want to know how to encode the public key and domain parameters so that the signature verifier decrypts it in order to use it. Because when you send them over the network to the verifier, you will need to encode as a single-byte array. I do not use the Bouncy Castle Provider. The whole implementation of the ECDSA algorithm is my project

+7
source share
2 answers

The points of an elliptic curve are almost always encoded using the encoding specified in X9.62.

It is not necessary to use point compression. It is trivial to encode using dot compression, but decoding a compressed point requires a bit more work, so if you really don't need to save extra bytes, I would not bother. Let me know if you need it and I will add details. You can recognize X9.62 encoded points with dot compression by the first byte, which will be 0x02 or 0x03.

Encoding without point compression is very simple: start with 0x04 (to indicate no compression). Then follow first with the x coordinate, then with the y coordinate, with zero padding on the left to the size in bytes of the field:

 int qLength = (q.bitLength()+7)/8; byte[] xArr = toUnsignedByteArray(x); byte[] yArr = toUnsignedByteArray(y); byte[] res = new byte[1+2*qLength]; res[0] = 0x04; System.arraycopy(xArr, 0, res, qLength - xArr.length, xArr.length); System.arraycopy(yArr, 0, res, 2* qLength - yArr.length, nLength); 

Decoding is, of course, trivial.

+9
source

I am sure that the BC implementation uses the X9.63 encoding, so they will be fairly standardized encodings. You will need to add the Bouncy Castle provider to your JRE ( Security.addProvider(new BouncyCastleProvider()) , see Security.addProvider(new BouncyCastleProvider()) Documentation.

 public static void showECKeyEncodings() { try { KeyPairGenerator kp = KeyPairGenerator.getInstance("ECDSA"); ECNamedCurveParameterSpec ecSpec = ECNamedCurveTable .getParameterSpec("prime192v1"); kp.initialize(ecSpec); KeyPair keyPair = kp.generateKeyPair(); PrivateKey privKey = keyPair.getPrivate(); byte[] encodedPrivKey = privKey.getEncoded(); System.out.println(toHex(encodedPrivKey)); PublicKey pubKey = keyPair.getPublic(); byte[] encodedPubKey = pubKey.getEncoded(); System.out.println(toHex(encodedPubKey)); KeyFactory kf = KeyFactory.getInstance("ECDSA"); PublicKey pubKey2 = kf.generatePublic(new X509EncodedKeySpec(encodedPubKey)); if (Arrays.equals(pubKey2.getEncoded(), encodedPubKey)) { System.out.println("That worked for the public key"); } PrivateKey privKey2 = kf.generatePrivate(new PKCS8EncodedKeySpec(encodedPrivKey)); if (Arrays.equals(privKey2.getEncoded(), encodedPrivKey)) { System.out.println("That worked for the private key"); } } catch (GeneralSecurityException e) { throw new IllegalStateException(e); } } 
+3
source

All Articles