## Elliptic Curve Cryptography (ECC) support

## Introduction

The IPWorks Encrypt development library supports Elliptic Curve Cryptography in a single unified
API via the `ECC` component. This component implements the following standards: ECDSA (Elliptic Curve Digital Signature Algorithm), EdDSA (Edwards-curve Digital Signature Algorithm), ECDH (Elliptic Curve Diffie Hellman), and ECIES (Elliptic Curve Integrated Encryption Scheme).
Using these standards, the `ECC` component supports creating ECC keys, computing a shared secret, signing and verifying signatures, and encrypting and decrypting data.

This guide will cover the basics for each of these fundamental operations.

#### Contents

- ECC keys
- Generating a shared secret with ECDH
- Signing with ECDSA and EdDSA
- Verifying signatures with ECDSA and EdDSA
- Encrypting with ECIES
- Decrypting with ECIES

## ECC keys

The `ECC` component supports the following curves and corresponding key types:

- secp256r1 (NIST P-256)
- secp384r1 (NIST P-384)
- secp521r1 (NIST P-521)
- X25519
- Ed25519
- X448
- Ed448

ECC keys come in pairs, one private and one public key. The mathematical parameters of these keys depends upon the specific ECC curve.
For the NIST curves (`secp256r1`, `secp384r1`, `secp521r1`), the public key consists of two parameters, `Rx` and `Ry`;
the private key consists of only one parameter value, `K`. For `Curve25519` and `Curve448` curves, the public key consists of one parameter, `XPk`,
and the private key consists of one parameter, `XSk`.

#### Creating ECC keys

To generate new ECC keys, simply call the `CreateKey` method and pass the desired key type as a string. After calling `CreateKey`, the `Key` property will hold the paired public and private key.
The PEM-encoded string representation of the keys, as well as the mathematical parameters themselves, can be accessed via the this `Key` property. Below is an example in C#:

Ecc ecc = new Ecc();
ecc.CreateKey("X25519");
string priv = ecc.Key.PrivateKey; // PEM-encoded private key
string pub = ecc.Key.PublicKey; // PEM-encoded public key
byte[] XPk = ecc1.Key.XPkB; // public key parameter in raw bytes
byte[] XSk = ecc1.Key.XSkB; // private key parameter in raw bytes

Certain `ECC` component operations restrict the type of key that can be used. Each subsection devoted to a specific operation includes a list of key types that are applicable to that operation.

## Computing a shared secret

The `ECC` component can compute a shared secret between two parties using a public and private key. The ECDH standard is used to compute the shared secret.

To compute a shared secret, first set the public key in the `RecipientKey` property and the private key in the `Key` property. If necessary, set the
`ComputeSecretKDF` property to the hash or HMAC algorithm that should be applied to the raw secret. Then, call the `ComputeSecret` method
and the resulting value will be stored in the `SharedSecret` property.

#### Code sample

Below is an example of computing a shared secret between two separate entities in C#:

Ecc alice = new Ecc();
Ecc bob = new Ecc();
// alice and bob will both compute the same secret independently
alice.CreateKey("X25519");
string alicePubKey = alice.Key.PublicKey;
string alicePrivKey = alice.Key.PrivateKey;
bob.CreateKey("X25519");
string bobPubKey = bob.Key.PublicKey;
string bobPrivKey = bob.Key.PrivateKey;
alice.Reset();
bob.Reset();
// note: public keys must be exchanged between parties by some external mechanism
alice.Key.PrivateKey = alicePrivKey;
alice.RecipientKey.PublicKey = bobPubKey;
alice.UseHex = true; // hex-encodes the shared secret after computation for easier display
alice.ComputeSecret();
string aliceSecret = alice.SharedSecret;
bob.Key.PrivateKey = bobPrivKey;
bob.RecipientKey.PublicKey = alicePubKey;
bob.UseHex = true;
bob.ComputeSecret();
string bobSecret = bob.SharedSecret;
// aliceSecret and bobSecret will match

The following key types are supported for this operation:

## Signing

The `ECC` component supports signing data via the ECDSA or EdDSA standards. The component will use the key specified in the `Key` property
to hash input data and then sign the resulting hash. To sign a hash directly instead of computing it first, the `HashValue` property should be
set to the hash to sign.

If the input data is stored in a file, set the `InputFile` property to the appropriate file path. If the input data is stored in memory, set the `InputMessage` property
to the string containing the data. The .NET and Java editions also support inputing from a stream via the `SetInputStream` method.

The `HashAlgorithm` property determines the algorithm used for hash computation. The `Algorithm` property is used to determine the eligibility of the `Key` for this operation. Supported algorithms and key types are as follows:

Once the `Key`, input data, `Algorithm`, and `HashAlgorithm` have all been populated (or `HashValue`), simply call
the `Sign` method. The computed hash is stored in the `HashValue` property, and the signed hash is stored in the `HashSignature` property.

If the `Ed25519` or `Ed448` curves are used, two additional parameters are applicable:

`HashEdDSA``EdDSAContext`

The `HashEdDSA` property determines whether EdDSA keys should be used with a PureEdDSA algorithm (Ed25519/Ed448) or a HashEdDSA algorithm (Ed25519ph, Ed448ph).
By default, `HashEdDSA` is False and the component uses the PureEdDSA algorithm. Please note that setting `HashValue` and signing a hash directly is not
supported when signing with a PureEdDSA algorithm. The `EdDSAContext` configuration option is used to specify context data when using PureEdDSA algorithms.

After the `Sign` method has been called, the `Progress` event will fire with updates during hash computation. Signing the computed hash
is quick and does not require progress updates.

A code example that includes signing can be found at the bottom of the *Verifying signatures* section below.

## Verifying signatures

The `ECC` component supports verifying signatures created via the ECDSA and EdDSA standards. In order to verify a signature the component requires the hash signature itself, the
public key corresponding to the private key used to sign, and the original data that was signed.

The signature to verify should be set in the `HashSignature` property,
and the public key of the signing party should be set in the `SignerKey` property. If the data that was signed is stored in a file, the `InputFile` property
should be set to the appropriate file path. Otherwise, the `InputMessage` property should be set to the string holding the data.
The .NET and Java editions also support inputing from a stream via the `SetInputStream` method.

The `HashAlgorithm` property must be set to the appropriate hashing algorithm when the following curves are used: `secp256r1`, `secp384r1`, or `secp521r1`.
When using the `Ed25519` or `Ed448` curves, the `HashEdDSA` property and `EdDSAContext` configuration option may apply.
`HashEdDSA` determines whether to use a PureEdDSA algorithm (Ed25519/Ed448) or a HashEdDSA algorithm (Ed25519ph/Ed448ph). By default, `HashEdDSA` is `False` and
a PureEdDSA algorithm will be used. The `EdDSAContext` configuration option can be used to specify context data when using PureEdDSA algorithms.

Once these properties are set, simply call the `VerifySignature` method. The component will compute the hash for the specified data and use it to populate the
`HashValue` property. It will then verify the signature using the specified `SignerKey` and `HashSignature`. If the computed signature
matches the provided signature, the `VerifySignature` method will return `True`, otherwise it will return `False`.

To verify a hash signature without computing the hash first, simply set the `HashValue` property with the computed hash before calling `VerifySignature`.
This is not applicable when using a PureEdDSA algorithm like `Ed25519` or `Ed448`.

#### Code samples

Below is an example of signing and verifying a signature with a PureEdDSA algorithm in C#:

//Create an EdDSA key with Party 1
Ecc ecc1 = new Ecc();
ecc1.CreateKey("ed25519");
string ecc1_priv = ecc1.Key.PrivateKey;
string ecc1_pub = ecc1.Key.PublicKey;
//Sign the data on Party 1
string originalData = "test data";
ecc1.Reset();
ecc1.Key.PrivateKey = ecc1_priv;
ecc1.InputMessage = originalData;
ecc1.UseHex = true; //Hex encode the hash signature for ease of use.
ecc1.Sign();
string hashSignature = ecc1.HashSignature;
//Transmit the hash signature, public key, and original data to Party 2
//Verify the data on Party 2
Ecc ecc2 = new Ecc();
ecc2.SignerKey.PublicKey = ecc1_pub;
ecc2.InputMessage = originalData;
ecc2.HashSignature = hashSignature;
ecc2.UseHex = true; //Decode the hex encoded hash signature
bool isVerified = ecc2.VerifySignature();

Below is an example of verifying a signature directly without computing the hash first (using HashEdDSA) in C#:

//Create an EdDSA key with Party 1
Ecc ecc1 = new Ecc();
ecc1.CreateKey("Ed25519");
string ecc1_priv = ecc1.Key.PrivateKey;
string ecc1_pub = ecc1.Key.PublicKey;
//Sign the data on Party 1
string originalData = "test data";
ecc1.Reset();
ecc1.Key.PrivateKey = ecc1_priv;
ecc1.InputMessage = originalData;
ecc1.UseHex = true; //Hex encode the hash signature for ease of use.
ecc1.HashEdDSA = true; // Use "Ed25519ph"
ecc1.Sign();
string computedHash = ecc1.HashValue;
string hashSignature = ecc1.HashSignature;
//Transmit the hash signature, public key, and computed hash to Party 2
//Verify the data on Party 2
Ecc ecc2 = new Ecc();
ecc2.SignerKey.PublicKey = ecc1_pub;
ecc2.HashValue = computedHash;
ecc2.HashSignature = hashSignature;
ecc2.HashEdDSA = true;
ecc2.UseHex = true; //Decode the hex encoded hash signature
bool isVerified = ecc2.VerifySignature();

The following algorithms and key types are applicable for this operation:

## Encrypting

The `ECC` component supports encrypting and decrypting data via the ECIES standard. Encryption requires an ECDSA public key, which should be set in the `RecipientKey` property.
The `Algorithm` field of the `ReceipientKey` will be used to determine the eligibility of the key for encryption operations. Supported key types are as follows:

- secp256r1
- secp384r1
- secp521r1

During encryption, the ECC key is used to generate a shared secret that both sides can use to encrypt or decrypt the data. The `EncryptionAlgorithm` property determines the symmetric encryption algorithm to use with this shared secret.
The `HMACAlgorithm` property determines the hashing algorithm that will generate a secure Message Authentication Code during encryption to verify the data's integrity.
The `HMACOptionalInfo` configuration option can be used to specify optional data used during the HMAC step of encryption and decryption (formatted as a hex string).
The `HMACKeySize` configuration option can be set if a specific key size is required during the HMAC step.

The `IV` property can be set to an
initialization vector used as input to the encryption function; by default the component will use an IV filled with null bytes, which is a standard practice since the encryption key
will only be used once. The `KDF` property specifies the Key Derivation Function used to convert a shared secret into an encryption key, and the `KDFHashAlgorithm` property
specifies the hash algorithm to use during this step. The `KDFOptionalInfo` configuration setting can be used to specify optional data for this step (formatted as a hex string).

In addition to the encryption parameters, the input data must be specified. If the data is held in a file, the `InputFile` property should be set to the appropriate file path.
Otherwise, the `InputMessage` property should be set to the string representation of the data. The .NET and Java editions also support inputing from a stream via the `SetInputStream` method.

Once these properties are configured, simply call the `Encrypt` method and the encrypted data will be available in the `OutputMessage` property. If the
`OutputFile` property is set or `SetOutputStream` is called prior to encryption, the encrypted data will instead be written to the appropriate file or stream.

A code example that includes encryption can be found at the bottom of the *Decrypting* section below.

## Decrypting

The `ECC` component supports encrypting and decrypting data via the ECIES standard. Decryption requires an ECDSA private key that is paired with the public key used to encrypt, and this private key should be set in the `Key` property.
The `Algorithm` field of the specified `Key` is used to determine the eligibility of the key for this operation. Supported key types are as follows:

- secp256r1
- secp384r1
- secp521r1

During decryption, the ECC key is used to generate a shared secret that both sides can use to encrypt or decrypt the data. The `EncryptionAlgorithm` property should be set to the symmetric encryption algorithm that was used with this shared secret to encrypt the data.
The `HMACAlgorithm` property should be set to the hashing algorithm that was used to generate a secure Message Authentication Code during encryption.
The `HMACOptionalInfo` configuration option can be used to specify optional data used during the HMAC step (only required if optional data was also specified prior to encryption).
The `HMACKeySize` configuration option can be set if a specific key size is required during the HMAC step.

The `IV` property can be set to an
initialization vector if an IV was used as input to the encryption function; by default the component will use an IV filled with null bytes, which is a standard practice since the encryption key
will only be used once. The `KDF` property should be set to the Key Derivation Function (used to convert a shared secret into an encryption key) that was used during encryption, and the `KDFHashAlgorithm` property
should be set to the hash algorithm that was used during this step while encrypting. The `KDFOptionalInfo` configuration setting can be used to specify optional data for this step (only required if optional data was also specified prior to encryption).

Once the decryption parameters are set, the input data must be specified. If the data is held in a file, the `InputFile` property should be set to the appropriate file path.
Otherwise, the `InputMessage` property should be set to the string representation of the data. The .NET and Java editions also support inputing from a stream via the `SetInputStream` method.

Once these properties are configured, simply call the `Decrypt` method and the decrypted data will be available in the `OutputMessage` property. If the
`OutputFile` property is set or `SetOutputStream` is called prior to encryption, the encrypted data will instead be written to the appropriate file or stream.

#### Code sample

Below is an example of encrypting and decrypting data in C#:

//Create an ECDSA key with Party 2
Ecc ecc2 = new Ecc();
ecc2.CreateKey("secp256r1");
string ecc2_priv = ecc2.Key.PrivateKey;
string ecc2_pub = ecc2.Key.PublicKey;
//Transmit public key to Party 1
//Encrypt the message on Party 1 using public key from Party 2
Ecc ecc1 = new Ecc();
ecc1.KDF = "KDF1"; //Use KDF1
ecc1.EncryptionAlgorithm = EccEncryptionAlgorithms.iesAES;
ecc1.KDFHashAlgorithm = EccKDFHashAlgorithms.iesSHA1;
ecc1.Config("KDFOptionalInfo=202122232425262728292a2b2c2d2e2f"); //optional Hex encoded string
ecc1.InputMessage = "test data";
ecc1.RecipientKey.PublicKey = ecc2_pub;
ecc1.UseHex = true;
ecc1.Encrypt();
string encryptedMessage = ecc1.OutputMessage;
//Transmit the encrypted message to Party 2
//Decrypt the message using the private key for Party 2
ecc2.KDF = "KDF1";
ecc2.EncryptionAlgorithm = EccEncryptionAlgorithms.iesAES;
ecc2.KDFHashAlgorithm = EccKDFHashAlgorithms.iesSHA1;
ecc2.Config("KDFOptionalInfo=202122232425262728292a2b2c2d2e2f");
ecc2.Key.PrivateKey = ecc2_priv;
ecc2.InputMessage = encryptedMessage;
ecc2.UseHex = true;
ecc2.Decrypt();
Console.WriteLine(ecc2.OutputMessage);

We appreciate your feedback. If you have any questions, comments, or suggestions about this article please contact our support team at kb@nsoftware.com.