10

I am developing Distributed digital signature that signs a document and send it through network to the Application Server.I am using socket programming in java to do it. I think the public key should be encoded or compressed i.e the x and y values are somehow represented as a single binary data and saved in a public registry or network.But i don't know how to do it 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 verifier of the signature will decode it to use it.because when you send them over the network to the verifier u gonna have to encode the as a single byte array.i am no using Bouncy Castle Provider. The whole implementation of ECDSA algorithm is my project

Clickmit Wg
  • 523
  • 2
  • 9
  • 25
  • How do you represent them in memory? They're just big integers, serializing them should be easy. – CodesInChaos Jun 07 '12 at 16:46
  • Do you want to use point compression? That's a technique where you only serialize the x coordinate and the sign of the y coordinate, and then use the curve equation to restore the y coordinate. – CodesInChaos Jun 07 '12 at 16:47
  • yes, but in addition to compression i want to put the compressed public key in shared network registry so two or more application servers will use it to verify the signature. – Clickmit Wg Jun 07 '12 at 17:21
  • What API are you using? E.g. what is the FQN class name for crypto instance and ECKeyPair class? Though as it been said, you could retrieve BigInteger values and store those as is. – Eugene Kuleshov Jun 07 '12 at 17:48
  • class for crypto instance is my own. – Clickmit Wg Jun 08 '12 at 03:00
  • see for newly edited code above – Clickmit Wg Jun 08 '12 at 03:08

2 Answers2

12

Elliptic curve points are almost always encoded using the encoding specified in X9.62.

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

Encoding without point compression is really simple: start with a 0x04 (to indicate no compression). Then follow with first the x coordinate, then the y coordinate, both zero-padded on the left up 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 this is of course trivial.

Rasmus Faber
  • 48,631
  • 24
  • 141
  • 189
  • thanks, i understand ur answer. where the public key should i save in order be used by one or more app server on the remote area? – Clickmit Wg Jun 08 '12 at 03:42
  • what about the domain parameters (q,a,b,G,n,h), how do they pass to the remote signature verification apps,because there are dynamically choosing elliptic curves as u sign. p-192, p-224, ....,p-512 recommended elliptic curve domain parameters – Clickmit Wg Jun 08 '12 at 04:01
  • @Clickmit: I assumes you had static domain parameters and just hardcoded them in each end. If you just have a small list of supported curves, I would just do something like prepending an integer specifying which curve you are using. If you want to encode all the domain parameters, there are standards for that too (lookup the ECDomainParameters ASN.1 structure), but I think you should find a ASN.1 DER encoder for that. Hand-coding the encoding of such a structure is not trivial. – Rasmus Faber Jun 08 '12 at 06:06
  • Is it possible to add the procedure to work with compressed keys? Thx – CarlosRos Sep 08 '17 at 15:44
  • could you please help on decoding compressed point ? - @RasmusFaber [link](https://stackoverflow.com/questions/64862815/how-to-decompress-x9-62-coordinate) – user2748161 Nov 16 '20 at 17:55
4

I'm pretty sure that the BC implementation uses X9.63 encoding, so these would be rather standardized encodings. You will need to add the Bouncy Castle provider to your JRE (Security.addProvider(new BouncyCastleProvider()), see the bouncy 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);
    }

}
Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • I am not reusing the Bouncy Castle implementation of ECDSA. i am implementing on my own but i got difficulty on encoding of the Domain parameters in order to send them over network as a single byte array and they should be decoded at the verifier side – Clickmit Wg Jun 09 '12 at 12:08
  • 1
    In that case I would implore you to look at the very permissive underlying Bouncy Castle implementation, if not for copying then just to look the standard X9.62 encoding of the domain parameters. BSI TR-03111 also has a (simpler) method of encoding domain parameters. – Maarten Bodewes Jun 10 '12 at 17:14
  • 1
    This example also seems to work in JDK 1.8 except you need to pass "EC" to the KeyPairGenerator and KeyFactory. – kravietz Mar 18 '16 at 09:32
  • 1
    Also "prime192v1" needs to be replaced by "secp192r1" in JDK 1.8. – kravietz Mar 18 '16 at 11:48
  • 1
    @kravietz Yeah, and you need to use `ECGenParameterSpec` as well for the key pair generator. I'll edit the answer to reflect those changes asap. Funny enough the BC and Oracle encoding differ; the private key contains the (optional) public key in case of Oracles' ASN.1 encoding, and it doesn't for BC. So both are correct and compatible, they just differ slightly. – Maarten Bodewes Mar 18 '16 at 13:11
  • 1
    @K.Os Please do not do that. SO is a team effort, I don't give personal advice here. – Maarten Bodewes Dec 05 '18 at 11:59