So Alice is sending a one-way message to Bob. Alice and Bob both, of course, have their own ECDH private keys, as well as each other's public keys.
I am using BouncyCastle 2.2.1 (BC) in this code. It appears (am I wrong?) that Alice and Bob must have the same Derivation and Encoding vectors (dV and eV) to encrypt a given message from one to the other. I've dug around in the metadata-decompiled code and it appears (again, am I wrong?) that these two values are merely added entropy along with a calculation that has to be made with "my" private and "their" public key anyway.
I adapted my code from this sample, and my google-fu gave out looking for the details on the inputs to IesWithCipherParameters().
MY QUESTION: Are these two values (dV and eV) similar to a block-cipher's initialization vector that is permitted to be sent in the clear?
Here is the complete .NET 6 Console app:
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Agreement;
using Org.BouncyCastle.Crypto.Agreement.Kdf;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Macs;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Paddings;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Prng;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
internal class Program
{
public static void Main()
{
CryptoApiRandomGenerator carng = new CryptoApiRandomGenerator();
var secureRandom = new SecureRandom(carng);
var ecParams = ECNamedCurveTable.GetByName("P-256");
var ecDomainParams = new ECDomainParameters(ecParams.Curve, ecParams.G, ecParams.N, ecParams.H, ecParams.GetSeed());
var ecKeyGenParams = new ECKeyGenerationParameters(ecDomainParams, secureRandom);
var ecGenerator = new ECKeyPairGenerator();
ecGenerator.Init(ecKeyGenParams);
var kpAlice = ecGenerator.GenerateKeyPair();
var kpBob = ecGenerator.GenerateKeyPair();
var messageOriginal = "I am the very model of a modern major general";
var messageOriginalBytes = Encoding.UTF8.GetBytes(messageOriginal);
var dV = new byte[8];
var eV = new byte[8];
secureRandom.NextBytes(dV);
secureRandom.NextBytes(eV);
var ciphertextBytes = Encrypt(kpAlice.Private, kpBob.Public, dV, eV, messageOriginalBytes);
// we are sending Bob the dV and eV values in the clear. Is that right? Doesn't seem right.
var decryptedBytes = Decrypt(kpAlice.Public, kpBob.Private, dV, eV, ciphertextBytes);
var decryptedString = Encoding.UTF8.GetString(decryptedBytes);
if (messageOriginal == decryptedString)
Console.WriteLine("it worked");
else
Console.WriteLine("it failed");
}
public static byte[] Encrypt(AsymmetricKeyParameter senderPrivate, AsymmetricKeyParameter recipientPublic, byte[] dV, byte[] eV, byte[] plaintextBytes)
{
//
// AES with CBC
//
BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CbcBlockCipher(new AesEngine()));
var iesEngine = new IesEngine(
new ECDHBasicAgreement(),
new Kdf2BytesGenerator(new Sha256Digest()),
new HMac(new Sha1Digest()),
cipher);
var p = new IesWithCipherParameters(dV, eV, 64, 128);
iesEngine.Init(true, senderPrivate, recipientPublic, p);
var ciphertext = iesEngine.ProcessBlock(plaintextBytes, 0, plaintextBytes.Length);
return ciphertext;
}
public static byte[] Decrypt(AsymmetricKeyParameter senderPublic, AsymmetricKeyParameter recipientPrivate, byte[] dV, byte[] eV, byte[] ciphertextBytes)
{
//
// AES with CBC
//
BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CbcBlockCipher(new AesEngine()));
var iesEngine = new IesEngine(
new ECDHBasicAgreement(),
new Kdf2BytesGenerator(new Sha256Digest()),
new HMac(new Sha1Digest()),
cipher);
var p = new IesWithCipherParameters(dV, eV, 64, 128);
iesEngine.Init(false, recipientPrivate, senderPublic, p);
var plaintextBytes = iesEngine.ProcessBlock(ciphertextBytes, 0, ciphertextBytes.Length);
return plaintextBytes;
}
}