Mutual Authentication With Public Key Encryption and Additional Data

The ECDH method that we use for key exchange on the Web is open to an Eve-in-the-Middle attack. For this, we add a digital signature with…

Mutual Authentication With Public Key Encryption and Additional Data

The ECDH method that we use for key exchange on the Web is open to an Eve-in-the-Middle attack. For this, we add a digital signature with either RSA or ECDSA to authenticate the server (Alice) to Bob. But, this approach only authenticates Alice to Bob, and not vice-versa. In many applications, we need authentication from both sides and also to add other data into the connection, such as the identity of a device.

For this, Bob and Alice will have long-term key pairs which identify them. As seen in Figure 1, these are static keys, and where the public key will be digitally signed by a trusted entity (Trent). Then, they will use ephemeral keys on either side for each connection they need to create. These keys will change for each connection, but the static keys will stay the same (but time-out after a given time).

Figure 1: Mutual authentication for key exchange

In the following case, we will use the SM2 public key encryption method, and which is a Chinese standard. First, we can create the four key pairs:

X9ECParameters x9ECParameters = GMNamedCurves.GetByName("sm2p256v1");


ECDomainParameters sm2Parameters = new ECDomainParameters(x9ECParameters.Curve, x9ECParameters.G, x9ECParameters.N);

Org.BouncyCastle.Crypto.Parameters.ECKeyGenerationParameters keygenParams = new Org.BouncyCastle.Crypto.Parameters.ECKeyGenerationParameters (sm2Parameters, new SecureRandom());

Org.BouncyCastle.Crypto.Generators.ECKeyPairGenerator generator = new Org.BouncyCastle.Crypto.Generators.ECKeyPairGenerator();

generator.Init(keygenParams);
var keyPair = generator.GenerateKeyPair();

var BobprivateKey = (ECPrivateKeyParameters) keyPair.Private;
var BobpublicKey = (ECPublicKeyParameters) keyPair.Public;

generator.Init(keygenParams);
keyPair = generator.GenerateKeyPair();

var BobEprivateKey = (ECPrivateKeyParameters) keyPair.Private;
var BobEpublicKey = (ECPublicKeyParameters) keyPair.Public;


keyPair = generator.GenerateKeyPair();
var AliceprivateKey = (ECPrivateKeyParameters) keyPair.Private;
var AlicepublicKey = (ECPublicKeyParameters) keyPair.Public;

generator.Init(keygenParams);
keyPair = generator.GenerateKeyPair();
var AliceEprivateKey = (ECPrivateKeyParameters) keyPair.Private;
var AliceEpublicKey = (ECPublicKeyParameters) keyPair.Public;

This gives us two static key pairs (BobprivateKey/BobpublicKey and AliceprivateKey/AlicepublicKey), and two ephemeral key pairs (BobEprivateKey/BobEpublicKey and AliceEprivateKey/AliceEpublicKey),

Alice can then initiate the key exchange, and receive Bob’s public with:

var exch = new Org.BouncyCastle.Crypto.Agreement.SM2KeyExchange();


exch.Init(new ParametersWithID(new
SM2KeyExchangePrivateParameters(true ,AliceprivateKey,AliceEprivateKey),
Strings.ToByteArray(bobID)));

byte[] kAlice = exch.CalculateKey(keysize,
new ParametersWithID(new SM2KeyExchangePublicParameters(BobpublicKey,
BobEpublicKey), Strings.ToByteArray(aliceID)));

and where bobID and aliceID are additional identity strings that can bind the key exchange. Bob then should compute the same key with:

exch = new Org.BouncyCastle.Crypto.Agreement.SM2KeyExchange();

exch.Init(new ParametersWithID(new SM2KeyExchangePrivateParameters(false,
BobprivateKey,BobEprivateKey),Strings.ToByteArray(aliceID)));

byte[] kBob = exch.CalculateKey(keysize, new ParametersWithID(new SM2KeyExchangePublicParameters(AlicepublicKey,AliceEpublicKey),
Strings.ToByteArray(bobID)));

The full code is [here]:

namespace SM2_Keyex
{

using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Asn1.X9;

using Org.BouncyCastle.Asn1.GM;
using Org.BouncyCastle.Utilities;

class Program
{

static void Main(string[] args)
{

try {

var curvename="sm2p256v1";
var bobID="[email protected]";
var aliceID="[email protected]";
var keysize=128;

if (args.Length >0) keysize=Convert.ToInt32(args[0]);
if (args.Length >1) bobID=args[1];
if (args.Length >2) aliceID=args[2];


X9ECParameters x9ECParameters = GMNamedCurves.GetByName(curvename);



ECDomainParameters sm2Parameters = new ECDomainParameters(x9ECParameters.Curve, x9ECParameters.G, x9ECParameters.N);

Org.BouncyCastle.Crypto.Parameters.ECKeyGenerationParameters keygenParams = new Org.BouncyCastle.Crypto.Parameters.ECKeyGenerationParameters (sm2Parameters, new SecureRandom());

Org.BouncyCastle.Crypto.Generators.ECKeyPairGenerator generator = new Org.BouncyCastle.Crypto.Generators.ECKeyPairGenerator();

generator.Init(keygenParams);
var keyPair = generator.GenerateKeyPair();

var BobprivateKey = (ECPrivateKeyParameters) keyPair.Private;
var BobpublicKey = (ECPublicKeyParameters) keyPair.Public;


generator.Init(keygenParams);
keyPair = generator.GenerateKeyPair();

var BobEprivateKey = (ECPrivateKeyParameters) keyPair.Private;
var BobEpublicKey = (ECPublicKeyParameters) keyPair.Public;


keyPair = generator.GenerateKeyPair();
var AliceprivateKey = (ECPrivateKeyParameters) keyPair.Private;
var AlicepublicKey = (ECPublicKeyParameters) keyPair.Public;

generator.Init(keygenParams);
keyPair = generator.GenerateKeyPair();
var AliceEprivateKey = (ECPrivateKeyParameters) keyPair.Private;
var AliceEpublicKey = (ECPublicKeyParameters) keyPair.Public;




var exch = new Org.BouncyCastle.Crypto.Agreement.SM2KeyExchange();


exch.Init(new ParametersWithID(new SM2KeyExchangePrivateParameters(true ,AliceprivateKey,AliceEprivateKey),Strings.ToByteArray(bobID)));

byte[] kAlice = exch.CalculateKey(keysize, new ParametersWithID(new SM2KeyExchangePublicParameters(BobpublicKey,BobEpublicKey),
Strings.ToByteArray(aliceID)));

exch = new Org.BouncyCastle.Crypto.Agreement.SM2KeyExchange();

exch.Init(new ParametersWithID(new SM2KeyExchangePrivateParameters(false, BobprivateKey,BobEprivateKey),Strings.ToByteArray(aliceID)));

byte[] kBob = exch.CalculateKey(keysize, new ParametersWithID(new SM2KeyExchangePublicParameters(AlicepublicKey,AliceEpublicKey),
Strings.ToByteArray(bobID)));


Console.WriteLine("\n\nKey Alice:\t{0}",Convert.ToHexString(kAlice));
Console.WriteLine("Key Bob:\t{0}",Convert.ToHexString(kBob));


Console.WriteLine("=== Static keys ===");
Console.WriteLine("\n\nBob Static Private key {0}",BobprivateKey.D);
Console.WriteLine("Bob Static Public key {0}, {1}",BobpublicKey.Q.AffineXCoord,BobpublicKey.Q.AffineYCoord);
Console.WriteLine("\nAlice Static Private key {0}",AliceprivateKey.D);
Console.WriteLine("Alice Static Public key {0}, {1}",AlicepublicKey.Q.AffineXCoord,AlicepublicKey.Q.AffineYCoord);

Console.WriteLine("=== Ephemeral keys ===");

Console.WriteLine("\n\nBob Ephemeral Private key {0}",BobprivateKey.D);
Console.WriteLine("Bob Ephemeral Public key {0}, {1}",BobpublicKey.Q.AffineXCoord,BobpublicKey.Q.AffineYCoord);
Console.WriteLine("\nAlice Ephemeral Private key {0}",AliceprivateKey.D);
Console.WriteLine("Alice Ephemeral Public key {0}, {1}",AlicepublicKey.Q.AffineXCoord,AlicepublicKey.Q.AffineYCoord);

Console.WriteLine("\n\n== ECC Parameters {0} == ",curvename);
Console.WriteLine("ECC A={0}, B={1}, Order={2}",sm2Parameters.Curve.A,sm2Parameters.Curve.B,sm2Parameters.Curve.Order);
Console.WriteLine("\nECC N={0}, G={1}, H={2}",keygenParams.DomainParameters.N, keygenParams.DomainParameters.G,keygenParams.DomainParameters.H);


} catch (Exception e) {
Console.WriteLine("Error: {0}",e.Message);
}

}
}
}


We can generate variable key sizes, but typically it would be either 128 bits or 256 bits in length. A sample run for a 128 bit shared key is:

A sample run for a 128-bit key is [here]:

Key Alice:	A9B4598194A4A7FA93B1488E03219D08
Key Bob: A9B4598194A4A7FA93B1488E03219D08
Bob ID: [email protected]
Alice ID: [email protected]
=== Static keys ===
Bob Static Private key 22663629632319858499911831467800316779032123351317036294738147722932151044961
Bob Static Public key 2e024e12f1046808fdeb12535dc32ca910b1df719670c1309e5756c8363bd851, bbb76ab086084ecda8d866c1c1806e3bc15aaec73ef87df476f3e24ce14a7cad
Alice Static Private key 25704379927464203383792470642436765260982773552233098385500408151033422766094
Alice Static Public key ef32e3f459a73473a34520a4b13c93315712ffc31b08421b061759144523dfde, 7ef8d0f4bc581a0ede0280d9c035c3138153204e6438534a83cccbaf48a786e2
=== Ephemeral keys ===
Bob Ephemeral Private key 22663629632319858499911831467800316779032123351317036294738147722932151044961
Bob Ephemeral Public key 2e024e12f1046808fdeb12535dc32ca910b1df719670c1309e5756c8363bd851, bbb76ab086084ecda8d866c1c1806e3bc15aaec73ef87df476f3e24ce14a7cad
Alice Ephemeral Private key 25704379927464203383792470642436765260982773552233098385500408151033422766094
Alice Ephemeral Public key ef32e3f459a73473a34520a4b13c93315712ffc31b08421b061759144523dfde, 7ef8d0f4bc581a0ede0280d9c035c3138153204e6438534a83cccbaf48a786e2

A sample run for a 256-bit key is [here]:

Key Alice:	8AFDDCED1E280209319C1E30E2773AFA752C41A689595997E73E656E5D09AC58
Key Bob: 8AFDDCED1E280209319C1E30E2773AFA752C41A689595997E73E656E5D09AC58
Bob ID: [email protected]
Alice ID: [email protected]
=== Static keys ===
Bob Static Private key 9961657569207165213288658243160183756591630536646422832095952833975417070225
Bob Static Public key af4f696154f671e5bd2c108b3477c05e719e61f70ce18cee509807c526913401, e031fd2defb4f3ae6e78c67ff6cbab9d1d5e6807ed26c27d4438c206f6ac3501
Alice Static Private key 29191140555732067136790628671982194060002195813426885016916187114911668495454
Alice Static Public key 1166c34f114deba4e7379727edd6183f140dad99dc002f2d38d27dc4435909a6, 93817c339baa7a2ad14d95618b97f4f32c39fc0752bf37ce2be5960e7c6f4fcf
=== Ephemeral keys ===
Bob Ephemeral Private key 9961657569207165213288658243160183756591630536646422832095952833975417070225
Bob Ephemeral Public key af4f696154f671e5bd2c108b3477c05e719e61f70ce18cee509807c526913401, e031fd2defb4f3ae6e78c67ff6cbab9d1d5e6807ed26c27d4438c206f6ac3501
Alice Ephemeral Private key 29191140555732067136790628671982194060002195813426885016916187114911668495454
Alice Ephemeral Public key 1166c34f114deba4e7379727edd6183f140dad99dc002f2d38d27dc4435909a6, 93817c339baa7a2ad14d95618b97f4f32c39fc0752bf37ce2be5960e7c6f4fcf

== ECC Parameters sm2p256v1 ==
ECC A=fffffffeffffffffffffffffffffffffffffffff00000000fffffffffffffffc, B=28e9fa9e9d9f5e344d5a9e4bcf6509a7f39789f515ab8f92ddbcbd414d940e93, Order=115792089210356248756420345214020892766061623724957744567843809356293439045923
ECC N=115792089210356248756420345214020892766061623724957744567843809356293439045923, G=(32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7,bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0,1,fffffffeffffffffffffffffffffffffffffffff00000000fffffffffffffffc), H=1

Conclusions

Isn’t that a beautiful method, and we didn’t have to use digital signing in there at all? The method is defined here:

https://asecuritysite.com/bouncy/bc_sm2_keyex