Reputation: 1
I need help in decrypting the base64 string to get key in c#. I received this keyvalue from a callback url as a response. below is a response:
"keyMaterial": {
"cryptoAlg": "ECDH",
"curve": "curve25519",
"dhPublicKey": {
"expiry": "2024-07-20T08:38:26.973Z",
"parameters": "Ephemeral public key",
"keyValue": "BA5bNnUGeT8y3qoCBBQ+hz/+RUtTO0hV3yPJAR7/NFWJWVMF0Dz3hr/wqn62xztP6LSZXg/IEnpzIdvJkx3P/gI="
},
"nonce": "iJHjuaGcnjXqWo4Bgr4BmCEuCa5fA41vHlEnnzYwOOQ="
}
Can anyone help me to decrypt
"keyValue": "BA5bNnUGeT8y3qoCBBQ+hz/+RUtTO0hV3yPJAR7/NFWJWVMF0Dz3hr/wqn62xztP6LSZXg/IEnpzIdvJkx3P/gI="
as I am doing it for the first time
i tried to google the solution but the solution I am getting is in java format. Please help me do it in c#.
Upvotes: 0
Views: 169
Reputation: 49400
According to your description (and your data), the key agreement should be performed with ECDH and Curve25519.
This is actually a contradiction, as ECDH is used for curves of the short Weierstrass form. In contrast, Curve25519 is a Montgomery curve (defined e.g. in in RFC 7748) and the key agreement is carried out with X25519.
However, it is possible to perform ECDH on Wei25519. Wei25519 is the birational equivalent to Curve25519 in short Weierstrass form, whose parameters are defined e.g. here.
If the assumption that ECDH/Wei25519 is applied is true, the Base64 encoded uncompressed key BA5b...
you posted should fulfill the equation of Wei25519, which is indeed the case:
using System;
using System.Numerics;
...
byte[] key = Convert.FromBase64String("BA5bNnUGeT8y3qoCBBQ+hz/+RUtTO0hV3yPJAR7/NFWJWVMF0Dz3hr/wqn62xztP6LSZXg/IEnpzIdvJkx3P/gI=");
BigInteger xBN = new BigInteger(key[1..33], true, true);
BigInteger yBN = new BigInteger(key[33..], true, true);
BigInteger aBN = new BigInteger(Convert.FromHexString("2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa984914a144"), true, true);
BigInteger bBN = new BigInteger(Convert.FromHexString("7b425ed097b425ed097b425ed097b425ed097b425ed097b4260b5e9c7710c864"), true, true);
BigInteger pBN = new BigInteger(Convert.FromHexString("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed"), true, true);
BigInteger leftBN = BigInteger.ModPow(yBN, 2, pBN);
BigInteger rightBN = (BigInteger.ModPow(xBN, 3, pBN) + aBN * xBN + bBN) % pBN;
Console.WriteLine(leftBN == rightBN); // True, i.e. y^2 = x^3 + a*x + b (Wei25519)
ECDH/Wei25519 can be implemented e.g. with C#/BouncyCastle as follows:
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC;
using System;
...
// Wei25519: y^2 = x^3 + a*x + b
string pHex = "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed"; // p
string aHex = "2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa984914a144"; // a
string bHex = "7b425ed097b425ed097b425ed097b425ed097b425ed097b4260b5e9c7710c864"; // b
string nHex = "1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed"; // order
string hHex = "08"; // cofactor
string gUncompressedHex = "042aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaad245a20ae19a1b8a086b4e01edd2c7748d14c923d4d7e6d7c61b229e9c5a27eced3d9"; // generator point (uncompressed)
ECCurve wei25519 = new FpCurve(
new BigInteger(pHex, 16),
new BigInteger(aHex, 16),
new BigInteger(bHex, 16),
new BigInteger(nHex, 16),
new BigInteger(hHex, 16));
ECDomainParameters ecDomainParameters = new ECDomainParameters(
wei25519,
wei25519.DecodePoint(Convert.FromHexString(gUncompressedHex)),
wei25519.Order,
wei25519.Cofactor);
Key generation and key export/import is possible as follows:
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Security;
...
// key generation
ECKeyPairGenerator ecKeyPairGenerator = new ECKeyPairGenerator();
ECKeyGenerationParameters ecKeyGenerationParameters = new ECKeyGenerationParameters(ecDomainParameters, new SecureRandom());
ecKeyPairGenerator.Init(ecKeyGenerationParameters);
AsymmetricCipherKeyPair keypair = ecKeyPairGenerator.GenerateKeyPair();
ECPrivateKeyParameters privateKey = (ECPrivateKeyParameters)keypair.Private;
ECPublicKeyParameters publicKey = (ECPublicKeyParameters)keypair.Public;
// key export/import
byte[] d = privateKey.D.ToByteArrayUnsigned();
byte[] q = publicKey.Q.GetEncoded(false);
privateKey = new ECPrivateKeyParameters(new BigInteger(1, d), ecDomainParameters);
publicKey = new ECPublicKeyParameters(wei25519.DecodePoint(q), ecDomainParameters);
The shared secret is simply the x coordinate that results from the multiplication of the public key (of the other party) and the (own) private key:
byte[] sharedSecret = publicKey.Q.Multiply(privateKey.D).Normalize().AffineXCoord.GetEncoded();
The actual key is derived from this (both sides must agree on an algorithm in advance, e.g. HKDF).
Please note that in practice X25519/Curve25519 is almost always applied instead of ECDH/Wei25519, as the former is more efficient with regard to implementation and performance.
Upvotes: 0