Skip to main content

ECC ElGamal encryption and decryption

The Crypto Interface provides the following APIs for ElGamal encryption and decryption:

  • CRYPTO_INTERFACE_ECEG_init (initializes a context for either encryption or decryption)

  • CRYPTO_INTERFACE_ECEG_update

  • CRYPTO_INTERFACE_ECEG_final

  • CRYPTO_INTERFACE_ECEG_encrypt

  • CRYPTO_INTERFACE_ECEG_decrypt

  • CRYPTO_INTERFACE_ECEG_encryptPKCSv1p5

  • CRYPTO_INTERFACE_ECEG_decryptPKCSv1p5

The first three APIs allow for a streaming encryption or decryption using an ECEG_CTX context type, which is a raw encryption or decryption with no padding.

Similarly, the fourth and fifth APIs are used for one shot, context-free raw encryption or decryption. When using these APIs, take into account not only the size of each block of plaintext or ciphertext, but also the 4-byte counter.

Counter size

ElGamal works by turning a buffer of plaintext into an x-coordinate of a point on an elliptic curve. There is about a 50% chance that any given plaintext represents (in big-endian) such a coordinate; however, in case of failure, a counter must be prepended to try again. The size of this counter is not standardized, but typically 4 bytes are used in industry, and TrustCore SDK also abides by this standard.

Plaintext size

For raw encryption, the plaintext size in bytes must be 4 bytes smaller than the curve size in bytes (to account for the counter).

Ciphertext size

The ciphertext comes out to a larger size than that of the plaintext. It comes out to 2 points on the curve, i.e., four concatenated coordinates in total. For example, for P256 the ciphertext is 128 bytes in length.

Recovered plaintext size

For raw decryption, the recovered plaintext comes out to be the single x-coordinate of a point on the curve. The prepended counter is not removed so that the API is compatible with other encryption implementations that may use a different size counter. The user application is responsible for removing the counter. For example, on P256, the decrypted 128 bytes of ciphertext result in 32 bytes of recovered plaintext.

In addition to the raw encrypt and decrypt APIs, there are APIs that perform PKCS #1 v1.5 padding. The decrypt API removes the padding and counter, resulting in the original plaintext as it was encrypted:

CRYPTO_INTERFACE_ECEG_encryptPKCSv1p5(pPubKey, RANDOM_rngFun, g_pRandomContext, pMessage, messageLen, pCipher, NULL);
CRYPTO_INTERFACE_ECEG_decryptPKCSv1p5(pPrivKey, pCipher, cipherLen, pRecoveredMessage, NULL);

For PKCS #1 v1.5, the API internally pads with a minimum of 11 bytes in addition to the 4-byte counter; hence, the messageLen cannot be bigger than the curve size in bytes minus 15. For example, on P256, a 32-byte curve, messageLen may be no bigger than 17 bytes, which is sufficient to encrypt (for example) an AES-128-bit (16 byte) key. The output buffer pCipher must be big enough to hold the resulting ciphertext of four coordinates. For example, on P256, cipherLen would be 128. The last parameters are an unused extended context reserved for future purposes and should be NULL.

Complete example

A complete example may be found at:

${MSS_SRC_PKG}/src/crypto_interface/example/crypto_interface_ecc_eg_example.c