Introduction
This tip will help the reader in understanding how using C# .NET and Bouncy Castle built in library, one can encrypt and decrypt data in Elliptic Curve Cryptography.
Background
Before looking at the actual implementation, let's briefly understand some key elements.
Question: What is ECC?
Answer: ECC is an asymmetric cryptography algorithm which involves some high level calculation using mathematical curves to encrypt and decrypt data. It is similar to RSA as it's asymmetric but it uses a very small length key as compared to RSA.
Question: What is Bouncy Castle?
Answer: Bouncy Castle is an open source library in C# used for encryption. .NET has encryption classes but using Bouncy Castle makes your cryptography work quite easily.
Using the Code
In this tip, we will be writing code for the below mentioned steps of ECC.
ECC is an asymmetric cryptography algorithm which involves the following steps:
Encryption
- Define a Curve
- Generate public private Key pair using that curve, for both sender and receiver
- Generate a Shared secret key from the key pair
- From that shared secret key, generate an encryption key
- Using that encryption key and symmetric encryption algorithm, encrypt the data to send
Decryption
The sender will either share the curve with receiver or sender and receiver will have the same use for the same curve type. Also, sender will share its public key with receiver.
- Generate public private Key pair using the same curve for that curve. For receiver.
- Regenerate a shared secret key using private key of receiver and public key of sender.
- From that shared secret key, generate an encryption key
- Using that encryption key and symmetric encryption algorithm, decrypt the data
Now that we have gone through the steps, let's see each step with code.
Encryption Process
1: Define a Curve
string curveName = "P-521";
var ecP1 = AnssiNamedCurves.GetByName("FRP256v1");
var ecP21 = TeleTrusTNamedCurves.GetByName("brainpoolp512t1");
X9ECParameters ecP = NistNamedCurves.GetByName(curveName);
c = (FpCurve)ecP.Curve;
eCDomainParameters = new ECDomainParameters(ecP.Curve, ecP.G, ecP.N, ecP.H, ecP.GetSeed());
2: Generate public private Key pair using that curve. For Sender and receiver both
senderPrivate = ((ECPrivateKeyParameters)asymmetricCipherKeyPair.Private).D.ToByteArray();
senderPublic = ((ECPublicKeyParameters)asymmetricCipherKeyPair.Public).Q.GetEncoded();
3: Generate a Shared secret key from the key pair
public byte[] GetSharedSecretValue(bool isEncrypt=true)
{
ECDHCBasicAgreement eLacAgreement=new ECDHCBasicAgreement();
eLacAgreement.Init(asymmetricCipherKeyPair.Private);
ECDHCBasicAgreement acAgreement=new ECDHCBasicAgreement();
acAgreement.Init(asymmetricCipherKeyPairA.Private);
BigInteger eLA= eLacAgreement.CalculateAgreement(asymmetricCipherKeyPairA.Public);
BigInteger a = acAgreement.CalculateAgreement(asymmetricCipherKeyPair.Public);
if (eLA.Equals(a) && !isEncrypt)
{
return eLA.ToByteArray();
}
if (eLA.Equals(a) && isEncrypt)
{
return a.ToByteArray();
}
return null;
}
4: From that shared secret key, generate an encryption key
public byte[] DeriveSymmetricKeyFromSharedSecret(byte[] sharedSecret)
{
Org.BouncyCastle.Crypto.Agreement.Kdf.ECDHKekGenerator egH=
new ECDHKekGenerator( DigestUtilities.GetDigest("SHA256
egH.Init(new DHKdfParameters(NistObjectIdentifiers.Aes,sharedSecret.Length,sharedSecret));
byte[] symmetricKey = new byte[ DigestUtilities.GetDigest("SHA256").GetDigestSize()];
egH.GenerateBytes(symmetricKey, 0,symmetricKey.Length);
return symmetricKey;
}
5: Using that encryption key and symmetric encryption algorithm, encrypt the data to send
public byte[] Encrypt(byte[] data, byte[] derivedKey)
{
byte[] output=null;
try
{
KeyParameter keyparam = ParameterUtilities.CreateKeyParameter("DES", derivedKey);
IBufferedCipher cipher = CipherUtilities.GetCipher("DES/ECB/ISO7816_4PADDING");
cipher.Init(true, keyparam);
try
{
output = cipher.DoFinal(data);
return output;
}
catch (System.Exception ex)
{
throw new CryptoException("Invalid Data");
}
}
catch(Exception ex)
{
}
return output;
}
Decryption Process
The sender will either share the curve with receiver or sender and receiver will have same use for the same curve type. Also sender will share its public key with receiver.
1: Generate public private Key pair using the same curve for that curve. For receiver.
asymmetricCipherKeyPairA = g.GenerateKeyPair();
recieverPrivate = ((ECPrivateKeyParameters)asymmetricCipherKeyPairA.Private).D.ToByteArray();
recieverPublic = ((ECPublicKeyParameters)asymmetricCipherKeyPairA.Public).Q.GetEncoded();
2: Regenerate a shared secret key using private key of receiver and public key of sender.
3: From that shared secret key, generate an encryption key
4: Using that encryption key and symmetric encryption algorithm, decrypt the data.
public byte[] Decrypt(byte[] cipherData, byte[] derivedKey)
{
byte[] output=null;
try
{
KeyParameter keyparam = ParameterUtilities.CreateKeyParameter("DES", derivedKey);
IBufferedCipher cipher = CipherUtilities.GetCipher("DES/ECB/ISO7816_4PADDING");
cipher.Init(false, keyparam);
try
{
output = cipher.DoFinal(cipherData);
}
catch (System.Exception ex)
{
throw new CryptoException("Invalid Data");
}
}
catch (Exception ex)
{
}
return output;
}
So, this is how we encrypt and decrypt a message in ECC.
Points of Interest
In order to first understand the working of ECC, I had to go through many specifications and Googling. Then, the main point and reason for me to write this tip is because there was nowhere on the internet where we could have a direct Bouncy Castle C# implementation of ECC given.
Although there is built-in .NET ECDiffieHellman
class for ECC, I have not explored it because my main requirement was to use Bouncy Castle.
History
- 13th January, 2016: First draft