With ECIES, we use the public key from Elliptic Curve Cryptography in order to derive a symmetric key.
ECIES (Elliptic Curve Integrated Encryption Scheme) using Bouncy Castle and C# |
Theory
In this method Alice generates a random private key (\(d_A\)) and the takes a point on an elliptic curve (\(G\)) and then determines her public key (\(Q_A\)):
\(Q_A = d_A \times G\)
G and \(Q_A\) are thus points on an elliptic curve. Alice then sends \(Q_A\) to Bob. Next Bob will generate:
\(R = r \times G\)
\(S = r \times Q_A\)
and where r is a random number generated by Bob. The symmetric key (S) is then used to encrypt a message.
Alice will then receive the encrypted message along with \(R\). She is then able to determine the same encryption key with::
\(S = d_A \times R\)
which is:
\(S = d_A \times (r \times G)\)
\(S = r \times (d_A \times G)\)
\(S = r \times Q_A\)
and which is the same as the key that Bob generated.
The method is illustrated here:
Code
First we create a folder named "bc_ecies", and then go into that folder.We can create a Dotnet console project for .NET 8.0 with:
dotnet new console --framework net8.0
Next some code:
namespace ECIES { using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Engines; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Security; using Org.BouncyCastle.Crypto.Generators; using System.Text; using Org.BouncyCastle.Asn1.Pkcs; using Org.BouncyCastle.Pkcs; using Org.BouncyCastle.X509; using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Crypto.EC; using Org.BouncyCastle.Crypto.Agreement; using Org.BouncyCastle.Crypto.Digests; using Org.BouncyCastle.Crypto.Macs; class Program { static void Main(string[] args) { string str="Hello"; var curvename="secp256k1"; if (args.Length >0) str=args[0]; if (args.Length >1) curvename=args[1]; try { ECKeyPairGenerator gen = new ECKeyPairGenerator(); SecureRandom secureRandom = new SecureRandom(); X9ECParameters ecps = CustomNamedCurves.GetByName(curvename); ECDomainParameters ecDomainParameters = new ECDomainParameters(ecps.Curve, ecps.G, ecps.N, ecps.H, ecps.GetSeed()); ECKeyGenerationParameters ecKeyGenerationParameters = new ECKeyGenerationParameters(ecDomainParameters, secureRandom); gen.Init(ecKeyGenerationParameters); var Bob= gen.GenerateKeyPair(); var Alice= gen.GenerateKeyPair(); var d = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; var e = new byte[] { 8, 7, 6, 5, 4, 3, 2, 1 }; var p = new IesWithCipherParameters(d, e, 64, 128); // Encrypt var cryptEng = new IesEngine(new ECDHBasicAgreement(),new Kdf2BytesGenerator(new Sha256Digest()), new HMac(new Sha256Digest())); cryptEng.Init(true, Bob.Private, Alice.Public, p); byte[] data = Encoding.ASCII.GetBytes(str); byte[] enc = cryptEng.ProcessBlock(data,0, data.Length); // Decrypt var decryptEng = new IesEngine(new ECDHBasicAgreement(),new Kdf2BytesGenerator(new Sha256Digest()), new HMac(new Sha256Digest())); decryptEng.Init(true, Bob.Private, Alice.Public, p); byte[] plain = decryptEng.ProcessBlock(enc,0,data.Length); var p1=new byte[data.Length]; Buffer.BlockCopy(plain, 0, p1, 0, data.Length); Console.WriteLine("Plain: {0} ",str); Console.WriteLine("Cipher: {0} [{1}]",Convert.ToHexString(enc),Convert.ToBase64String(enc)); Console.WriteLine("Decrypted: {0}" ,System.Text.Encoding.UTF8.GetString(p1)); Console.WriteLine("\n== Curve: {0} ",curvename); Console.WriteLine("\n==Alice keys == "); var privateKey = (ECPrivateKeyParameters) Alice.Private; var publicKey = (ECPublicKeyParameters) Alice.Public; Console.WriteLine("\n == Private key === "); Console.WriteLine(" == D ==={0} ",privateKey.D.ToString()); Console.WriteLine(" == Public key === "); Console.WriteLine(" == Q_x ==={0} ",publicKey.Q.XCoord); Console.WriteLine(" == Q_t ==={0} ",publicKey.Q.YCoord); Console.WriteLine("\n==Bob keys == "); privateKey = (ECPrivateKeyParameters) Bob.Private; publicKey = (ECPublicKeyParameters) Bob.Public; Console.WriteLine("\n == Private key === "); Console.WriteLine(" == D ==={0} ",privateKey.D.ToString()); Console.WriteLine(" == Public key === "); Console.WriteLine(" == Q_x ==={0} ",publicKey.Q.XCoord); Console.WriteLine(" == Q_t ==={0} ",publicKey.Q.YCoord); Console.WriteLine("\n\nCurve details: G={0}, N={1}, H={2}", ecps.G, ecps.N, ecps.H); Console.WriteLine("A={0}\nB={1}\nField size={2}",ecps.Curve.A,ecps.Curve.B,ecps.Curve.FieldSize); } catch (Exception e) { Console.WriteLine("Error: {0}",e.Message); } } } }
A sample run for the NIST P-256 curve:
Plain: Hello Cipher: 043EEBA057E58520398686865689A5AAA16DF19A10B5A2F8D2FB5C907664076B26C1B84C84 [BD7roFflhSA5hoaGVomlqqFt8ZoQtaL40vtckHZkB2smwbhMhA==] Decrypted: Hello == Curve: P-256 ==Alice keys == == Private key === == D ===20095745737963775254115792097819341569898246674422301374031596614518891314351 == Public key === == Q_x ===b3354e3c202077fb7e7d9aa75c0f7e47581fecb64620337c67f05c300c3fbb46 == Q_t ===a03a646e1eda0d777acdc09041b18080d2259ba1e80b560412d8a4b52a00f2d2 ==Bob keys == == Private key === == D ===77334438983487146498203856769750122534227946737471030687758663600349319254712 == Public key === == Q_x ===81a3d0b70c66f5fc4f16dabd4a9e3076b04a354c14ae9af1fbc6b3137206d48b == Q_t ===b5bbbb78c3ee099fb50941ba471ca2d14004e2e496bc5440bec4ff6d504091c1 Curve details: G=(6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296,4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5,1), N=115792089210356248762697446949407573529996955224135760342422259061068512044369, H=1 A=ffffffff00000001000000000000000000000000fffffffffffffffffffffffc B=5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b Field size=256
and:
Plain: Hello Cipher: CCE4EB9006114D4A0D14D5511A445A5127D4E367ACB32EC418F19A3C5F91CC6BA7BF824A91 [zOTrkAYRTUoNFNVRGkRaUSfU42essy7EGPGaPF+RzGunv4JKkQ==] Decrypted: Hello == Curve: secp256k1 ==Alice keys == == Private key === == D ===21780821407748287735342541217844678722456676556478844752016708485856950985750 == Public key === == Q_x ===503d543f2bbecd23796d739ea8c93420778d1eda09031ca36576b3e4b4966087 == Q_t ===df6f232e75960d8b61c5500ab26b2b731565c3e1b8ef7dea8241831a55b746c5 ==Bob keys == == Private key === == D ===22532829012982123891324214196055684259095217236742723653314344066250408526487 == Public key === == Q_x ===705089c082409f926bb6d5ae8c318c328b9f6b8e5ee383223410e2e7b54981b0 == Q_t ===96a8cf11ac102040df5a099e9f7b0c25d0027cb9ba3c2141d13d3ae27b96704f Curve details: G=(79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8,1), N=115792089237316195423570985008687907852837564279074904382605163141518161494337, H=1 A=0 B=7 Field size=256