javaencryptioncryptographyjacksonecies

Transferring ECIES public key to the client


I am new to ECIES and using ECIES algorithm for encryption and decryption. Below is the code snippet that I am using for the encryption and decryption mechanism.

    public static void main(String[] args) throws Exception {

      // Server Side Generates KeyPair
      KeyPair keyPair = serverSideKeyGeneration();

      // Client receives the KeyPair or Public Key before sending actual call to server
      String originalString = "Hello";
      byte[] ecryptedBase64Data = clientSideCodeToGenerateEncryptedData(originalString, keyPair);
      System.out.println("Encrypted Data" + ecryptedBase64Data);

      // Server receives the encrypted Data and decrypt using Private Key
      String originalValue = decryptEncodedString(keyPair, ecryptedBase64Data);
      System.out.println(originalValue);

    }

    private static byte[] clientSideCodeToGenerateEncryptedData(String originalString, KeyPair keyPair) throws Exception{
       Cipher cipher = Cipher.getInstance("ECIES");
       cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
       byte[] ecryptedBase64Data = Base64.encode(cipher.doFinal(originalString.getBytes("UTF-8")));
       return ecryptedBase64Data;

    }

   private static KeyPair serverSideKeyGeneration() throws Exception {
       Security.addProvider(new BouncyCastleProvider());

       KeyPairGenerator kpg = KeyPairGenerator.getInstance("ECIES");
       kpg.initialize(new ECGenParameterSpec("secp256r1"));

       // Key pair to store public and private key
       KeyPair keyPair = kpg.generateKeyPair();

       // System.out.println(keyPair.getPublic());
       // System.out.println(keyPair.getPrivate());

       return keyPair;

   }

   private static String decryptEncodedString(KeyPair keyPair, byte[] ret) throws Exception {
       Cipher iesCipherServer = Cipher.getInstance("ECIES");
       iesCipherServer.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
       String originalValue = new String(iesCipherServer.doFinal(Base64.decode(ret)));
       return originalValue;

   }

The above code snippet is working fine but what I want is that before any communication between the client and the server, the client will send a startup request and receive the public key at its end. Then will encrypt the payload using the public key and send the same to server and upon receiving, the server will decrypt the data using private key that has been generated earlier.

When I am using the below snippet to make the keyPair stored as JSON object it throws exception:

    MobileData data = new MobileData();
    data.setKeyPair(keyPair);

    ObjectMapper mapper = new ObjectMapper();
    String jsonString = mapper.writeValueAsString(data);

Exception:

org.codehaus.jackson.map.JsonMappingException: No serializer found for class org.bouncycastle.math.ec.WNafL2RMultiplier and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: MobileData["keyPair"]->java.security.KeyPair["public"]->org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey["parameters"]->org.bouncycastle.jce.spec.ECParameterSpec["curve"]->org.bouncycastle.math.ec.custom.sec.SecP256R1Curve["multiplier"])

How can I send the public key to the client?


Solution

  • The problem is that KeyPair can not be serialized as json. You need to send only the public key content

     public class MobileData{
            byte publicKeyEncoded[];
     }
    

    MobileData data = new MobileData();
    data.setPublicKeyEncoded(keyPair.getPublic().getEncoded());
    
    ObjectMapper mapper = new ObjectMapper();
    String jsonString = mapper.writeValueAsString(data);
    

    The public key will be encoded as base64 into the json string