diff --git a/LarpixServer/Account/Requests.cs b/LarpixServer/Account/Requests.cs
index 51f2419..d1c09cb 100644
--- a/LarpixServer/Account/Requests.cs
+++ b/LarpixServer/Account/Requests.cs
@@ -6,6 +6,7 @@ using LarpixServer.Filesystem;
using LarpixServer.Utils;
using LarpixServer.Utils.Jsons;
using static LarpixServer.Utils.Utils;
+using Org.BouncyCastle.Crypto.Parameters;
namespace LarpixServer.Account;
@@ -81,12 +82,10 @@ public class Requests
context.Response.ContentType = mimeTypes["json"];
- (BigInteger p, BigInteger g, BigInteger pubServer, BigInteger secretServer) serverInfo =
- Encryption.Encryption.Init();
+ var serverInfo = Encryption.Encryption.InitHybridKEM();
KeyExchangePayload payload = new KeyExchangePayload();
- payload.p = serverInfo.p.ToString();
- payload.g = serverInfo.g.ToString();
- payload.pubServer = serverInfo.pubServer.ToString();
+ payload.pubX25519 = Convert.ToBase64String(serverInfo.pubX25519);
+ payload.pubMlKem = Convert.ToBase64String(serverInfo.pubMlKem);
payload.idKey = DateTimeOffset.UtcNow.ToUnixTimeSeconds() + "\n";
while (createHolder.ContainsKey(payload.idKey))
@@ -96,7 +95,8 @@ public class Requests
CreateHolder dataHolder = new();
dataHolder.date = DateTimeOffset.UtcNow;
- dataHolder.serverInfo = serverInfo;
+ dataHolder.privX25519Server = serverInfo.privX25519;
+ dataHolder.privMlKemServer = serverInfo.privMlKem;
createHolder.TryAdd(payload.idKey, dataHolder);
@@ -123,9 +123,12 @@ public class Requests
}
entry.date = DateTimeOffset.UtcNow;
- entry.pubClient = BigInteger.Parse(serializedBody.pubClient);
- byte[] sharedKey = Encryption.Encryption.CalcCommunicationKey(entry.pubClient,
- entry.serverInfo.secretServer, entry.serverInfo.p);
+
+ byte[] pubX25519Client = Convert.FromBase64String(serializedBody.pubX25519);
+ byte[] ciphertextMlKem = Convert.FromBase64String(serializedBody.ciphertextMlKem);
+
+ byte[] sharedKey = Encryption.Encryption.CalcHybridSharedKey(
+ pubX25519Client, entry.privX25519Server, ciphertextMlKem, entry.privMlKemServer);
entry.name = Encryption.Encryption.Decrypt(serializedBody.username, sharedKey);
@@ -649,6 +652,6 @@ public class CreateHolder
public string name;
public string pass;
public string captcha;
- public (BigInteger p, BigInteger g, BigInteger pubServer, BigInteger secretServer) serverInfo;
- public BigInteger pubClient;
+ public X25519PrivateKeyParameters privX25519Server;
+ public MLKemPrivateKeyParameters privMlKemServer;
}
\ No newline at end of file
diff --git a/LarpixServer/Account/Utils.cs b/LarpixServer/Account/Utils.cs
index 5bf67c1..8a7f8ad 100644
--- a/LarpixServer/Account/Utils.cs
+++ b/LarpixServer/Account/Utils.cs
@@ -47,7 +47,7 @@ public class Utils
public static bool IsUserLocal(string usernameWD, out string domain)
{
- if (usernameWD.EndsWith(":" + DOMAIN))
+ if (!usernameWD.Contains(':') || usernameWD.EndsWith(":" + DOMAIN))
{
domain = DOMAIN;
return true;
diff --git a/LarpixServer/Encryption/Encryption.cs b/LarpixServer/Encryption/Encryption.cs
index 3d645c6..f7338d9 100644
--- a/LarpixServer/Encryption/Encryption.cs
+++ b/LarpixServer/Encryption/Encryption.cs
@@ -2,87 +2,60 @@ using System.Globalization;
using System.Numerics;
using System.Security.Cryptography;
using System.Text;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Kems;
+using Org.BouncyCastle.Security;
namespace LarpixServer.Encryption;
public class Encryption
{
- private static readonly string PrimeHex =
- "0" +
- "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
- "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
- "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
- "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
- "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" +
- "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" +
- "83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
- "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" +
- "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" +
- "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" +
- "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" +
- "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" +
- "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" +
- "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" +
- "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" +
- "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" +
- "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" +
- "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" +
- "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" +
- "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" +
- "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" +
- "FFFFFFFFFFFFFFFF";
-
- ///
- /// RFC 3526 4096-bit MODP Group (ID: 16) Prime
- ///
- public static BigInteger Prime { get; } = BigInteger.Parse(PrimeHex, NumberStyles.AllowHexSpecifier);
-
- public static void Chuj()
+ public static (byte[] pubX25519, X25519PrivateKeyParameters privX25519, byte[] pubMlKem, MLKemPrivateKeyParameters privMlKem) InitHybridKEM()
{
- (BigInteger p, BigInteger g, BigInteger pubServer, BigInteger secretServer) serverInfo = Init();
- (BigInteger pubClient, byte[] aesKey) clientInfo = CalcCommunicationKeyClient(serverInfo.p, serverInfo.g, serverInfo.pubServer);
- byte[] sharedKey = CalcCommunicationKey(clientInfo.pubClient, serverInfo.secretServer, serverInfo.p);
+ var random = new SecureRandom();
+
+ // X25519
+ var x25519KeyGen = new X25519KeyPairGenerator();
+ x25519KeyGen.Init(new X25519KeyGenerationParameters(random));
+ var x25519Kp = x25519KeyGen.GenerateKeyPair();
+
+ // ML-KEM-768
+ var mlkemGenParams = new MLKemKeyGenerationParameters(random, MLKemParameters.ml_kem_768);
+ var mlkemKeyGen = new MLKemKeyPairGenerator();
+ mlkemKeyGen.Init(mlkemGenParams);
+ var mlkemKp = mlkemKeyGen.GenerateKeyPair();
- if (sharedKey == clientInfo.aesKey)
- {
- Console.WriteLine("key ok");
- }
+ return (
+ ((X25519PublicKeyParameters)x25519Kp.Public).GetEncoded(),
+ (X25519PrivateKeyParameters)x25519Kp.Private,
+ ((MLKemPublicKeyParameters)mlkemKp.Public).GetEncoded(),
+ (MLKemPrivateKeyParameters)mlkemKp.Private
+ );
}
-
- public static (BigInteger p, BigInteger g, BigInteger pubServer, BigInteger secretServer) Init()
+
+ public static byte[] CalcHybridSharedKey(byte[] pubX25519Client, X25519PrivateKeyParameters privX25519Server, byte[] ciphertextMlKem, MLKemPrivateKeyParameters privMlKemServer)
{
- BigInteger p = Prime;//GenerateRandomBigInt(4096);
- BigInteger g = 2;
- BigInteger secretServer = GenerateRandomBigInt(4096);
+ // X25519 Agreement
+ var x25519Agreement = new Org.BouncyCastle.Crypto.Agreement.X25519Agreement();
+ x25519Agreement.Init(privX25519Server);
+ var secretX25519 = new byte[32];
+ x25519Agreement.CalculateAgreement(new X25519PublicKeyParameters(pubX25519Client), secretX25519, 0);
- BigInteger pubServer = BigInteger.ModPow(g, secretServer, p);
+ // ML-KEM Decapsulation
+ var decapsulator = new MLKemDecapsulator(MLKemParameters.ml_kem_768);
+ decapsulator.Init(privMlKemServer);
+ var secretMlKem = new byte[decapsulator.SecretLength];
+ decapsulator.Decapsulate(ciphertextMlKem, secretMlKem);
- return (p, g, pubServer, secretServer);
- }
-
- public static (BigInteger pubClient, byte[] aesKey) CalcCommunicationKeyClient(BigInteger p, BigInteger g, BigInteger pubServer)
- {
- BigInteger secretClient = GenerateRandomBigInt(4096);
-
- BigInteger pubClient = BigInteger.ModPow(g, secretClient, p);
+ // Combine and Hash: SHA256(X25519_Secret || MLKEM_Secret)
+ var combined = new byte[secretX25519.Length + secretMlKem.Length];
+ Buffer.BlockCopy(secretX25519, 0, combined, 0, secretX25519.Length);
+ Buffer.BlockCopy(secretMlKem, 0, combined, secretX25519.Length, secretMlKem.Length);
- BigInteger sharedSecret = BigInteger.ModPow(pubServer, secretClient, p);
-
- byte[] aesKey;
using (SHA256 sha256 = SHA256.Create())
{
- aesKey = sha256.ComputeHash(sharedSecret.ToByteArray(isUnsigned: true, isBigEndian: true));
- }
-
- return (pubClient, aesKey);
- }
-
- public static byte[] CalcCommunicationKey(BigInteger pubClient, BigInteger secretServer, BigInteger p)
- {
- BigInteger sharedSecret = BigInteger.ModPow(pubClient, secretServer, p);
- using (SHA256 sha256 = SHA256.Create())
- {
- return sha256.ComputeHash(sharedSecret.ToByteArray(isUnsigned: true, isBigEndian: true));
+ return sha256.ComputeHash(combined);
}
}
diff --git a/LarpixServer/LarpixServer.csproj b/LarpixServer/LarpixServer.csproj
index 07e209b..3caaaf2 100644
--- a/LarpixServer/LarpixServer.csproj
+++ b/LarpixServer/LarpixServer.csproj
@@ -8,6 +8,7 @@
+
diff --git a/LarpixServer/Utils/Jsons.cs b/LarpixServer/Utils/Jsons.cs
index ff9ad3e..54c94fc 100644
--- a/LarpixServer/Utils/Jsons.cs
+++ b/LarpixServer/Utils/Jsons.cs
@@ -21,15 +21,15 @@ public class Universal3String
public class KeyExchangePayload
{
- public string p { get; set; }
- public string g { get; set; }
- public string pubServer { get; set; }
+ public string pubX25519 { get; set; }
+ public string pubMlKem { get; set; }
public string idKey { get; set; }
}
public class KeyExchangePayloadClient
{
- public string pubClient { get; set; }
+ public string pubX25519 { get; set; }
+ public string ciphertextMlKem { get; set; }
public string idKey { get; set; }
public string username { get; set; }
public string password { get; set; }