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