0

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;
}

}

  • 1
    You are mostly correct that must be sent, however, these cannot add entropy to your private key since they are public. You are stuck at the 3rd step where KDF is used. I'm not sure which KDF is used, however, the IES must be init in the same way. – kelalaka Sep 29 '23 at 23:14
  • OK, so I have to send these two values (dV and eV), yes? But what I was really driving at, is whether it is okay to send them in the clear? By being stuck, did you mean to say that that is where the crux of the question lies? BTW in the Encrypt() method I am using the Kdf2BytesGenerator class with a Sha256Digest, in the IESEngine constructor. – Kerry Thomas Sep 29 '23 at 23:41
  • 1
    Ok, missed the KDF part. How can you send it encrypted if the receiver cannot recover encrypted messages without setting paremeters IesWithCipherParameters. The name is good, they are paremeters and sent to init... – kelalaka Sep 29 '23 at 23:45
  • So ... I am gathering that it is okay to send those two parameters in the clear, do I have that right? – Kerry Thomas Sep 29 '23 at 23:50
  • 1
    Yes, that's ok. That is the aim of the parameters. – kelalaka Sep 29 '23 at 23:54

0 Answers0