Search code examples
javaencryptioncryptographybouncycastleencryption-asymmetric

Encrypting with EC key: what's the use of IEKeySpec?


I try to encrypt/decrypt messages using a EC key. I created the key ussing openssl:

openssl ecparam -name prime256v1 -genkey -noout -out secp256r1-key.pem
openssl ec -in secp256r1-key.pem -pubout -out secp256r1-pub.pem
openssl req -new -key secp256r1-key.pem -x509 -nodes -days 99999 -out secp256r1-cert.pem

Created a java spring boot app using bouncy castle library for encryption:

   public String encrypt_1(final String msg, PublicKey publicKey) throws Exception {

        final IESCipher c1 = new org.bouncycastle.jcajce.provider.asymmetric.ec.IESCipher.ECIES();

        final Cipher cipher;
        cipher = Cipher.getInstance("ECIES");

        final byte[] msgBytes = msg.getBytes("UTF-8");

        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        final byte[] encryptedBytes = cipher.doFinal(msgBytes);

        return Base64.getEncoder().encodeToString(encryptedBytes);

    }

    public String decrypt_1(final String msgEncrypted, PrivateKey privateKey) throws Exception {
        final Cipher cipher = Cipher.getInstance("ECIES");

        final byte[] msgBytes = Base64.getDecoder().decode(msgEncrypted);

        cipher.init(Cipher.DECRYPT_MODE, privateKey);

        final byte[] decryptedJwtBytes = cipher.doFinal(msgBytes);

        return new String(decryptedJwtBytes, StandardCharsets.US_ASCII);
    }

This works as I have output. However when I see other people implementing ECIES in java they use IESParameterSpec and IEKeySpec with as input both public and private key of both own and foreign key (as it is asymetric). An example can be found here: https://gist.github.com/amrishodiq/9821413 or on stackOverflow: ECC algorithm key mismatch

They do something like:

...
        IESParameterSpec param = new IESParameterSpec(d, e, 256);

        // decrypt the text using the private key
        bcipher.init(Cipher.DECRYPT_MODE, new IEKeySpec(tpPrivateKey, ownPublicKey), param);
        final byte[] decryptedBytes = bcipher.doFinal(cipherTextBytes);

...

I can't get that code to work, but I want to know if this is more secure and why both keys are used at the same time during encryption/decryption.


Solution

  • You're missing some fundamental understanding here.

    You cannot encrypt per se with elliptic curves (ElGamal with an elliptic curve group is an exception, but not used in practice).

    "Encryption" in the context of elliptic curves is really the following process:

    • Knowing that an EC private key is a large number, and an EC public key is a (x,y) point on the curve's Cartesian plane.
    • Generating a shared symmetric key via elliptic curve Diffie Hellman.
    • This ECDH process requires input from two parties, where each party effectively calculates their private key * public point A * public point B.
    • This calculation will yield another shared secret point on the curve, next the x co-ordinate component of this new point is used and passed through a hashing function to generate uniform key material.
    • Finally, you use this key with a strong symmetric cipher, preferably something like ChaCha20-Poly1305.

    In summary, with EC crypto, first we do a little dance to agree a key, then we can use any symmetric cipher we like.

    It's that simple, don't get mired in unnecessary detail. Also move to a different library like libsodium if possible, BC is noisy.

    Finally,

            byte[]  d = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
            byte[]  e = new byte[] { 8, 7, 6, 5, 4, 3, 2, 1 };
            IESParameterSpec param = new IESParameterSpec(d, e, 256);
    

    The above "derivation and encoding vectors" are worthless.