From e66170563f015d4aa3dda0b4fcd54d849507d877 Mon Sep 17 00:00:00 2001 From: COM8 Date: Sun, 6 Jan 2019 11:46:32 +0100 Subject: [PATCH] Added SCRAM-SHA-256 support #51 --- .../SASL/SHA1/ScramSHA1SASLMechanism.cs | 14 +++- .../SASL/SHA1/ScramSHA256SASLMechanism.cs | 69 +++++++++++++++++++ .../XML/Messages/Processor/SASLConnection.cs | 6 +- XMPP_API/XMPP_API.csproj | 1 + 4 files changed, 87 insertions(+), 3 deletions(-) create mode 100644 XMPP_API/Classes/Network/XML/Messages/Features/SASL/SHA1/ScramSHA256SASLMechanism.cs diff --git a/XMPP_API/Classes/Network/XML/Messages/Features/SASL/SHA1/ScramSHA1SASLMechanism.cs b/XMPP_API/Classes/Network/XML/Messages/Features/SASL/SHA1/ScramSHA1SASLMechanism.cs index ace448753..2b744a0be 100644 --- a/XMPP_API/Classes/Network/XML/Messages/Features/SASL/SHA1/ScramSHA1SASLMechanism.cs +++ b/XMPP_API/Classes/Network/XML/Messages/Features/SASL/SHA1/ScramSHA1SASLMechanism.cs @@ -84,10 +84,15 @@ public override AbstractMessage generateResponse(AbstractMessage msg) // Throw wrong order } itersStr = itersStr.Substring(2); - if (!int.TryParse(itersStr, out int iters)) + int iters = -1; + if (!int.TryParse(itersStr, out iters)) { // Throw could not pars iterations } + else if (!isValidIterationsCount(iters)) + { + // Throw invalid iterations count + } return new ScramSha1ChallengeSolutionMessage(computeAnswer(iters)); } @@ -106,7 +111,7 @@ public override SelectSASLMechanismMessage getSelectSASLMechanismMessage() #endregion #region --Misc Methods (Private)-- - private string computeAnswer(int iterations) + protected string computeAnswer(int iterations) { string clientFinalMessageBare = "c=biws,r=" + serverNonce; byte[] saltBytes = Convert.FromBase64String(saltBase64); @@ -123,6 +128,11 @@ private string computeAnswer(int iterations) return encodeStringBase64(clientFinalMessage); } + protected virtual bool isValidIterationsCount(int iters) + { + return iters > 0; + } + #endregion #region --Misc Methods (Protected)-- diff --git a/XMPP_API/Classes/Network/XML/Messages/Features/SASL/SHA1/ScramSHA256SASLMechanism.cs b/XMPP_API/Classes/Network/XML/Messages/Features/SASL/SHA1/ScramSHA256SASLMechanism.cs new file mode 100644 index 000000000..601eb08ec --- /dev/null +++ b/XMPP_API/Classes/Network/XML/Messages/Features/SASL/SHA1/ScramSHA256SASLMechanism.cs @@ -0,0 +1,69 @@ +namespace XMPP_API.Classes.Network.XML.Messages.Features.SASL.SHA1 +{ + public class ScramSHA256SASLMechanism : ScramSHA1SASLMechanism + { + // https://tools.ietf.org/html/rfc7677 + //--------------------------------------------------------Attributes:-----------------------------------------------------------------\\ + #region --Attributes-- + private const byte CLIENT_NONCE_LENGTH = 32; + + private readonly string CLIENT_NONCE_BASE_64; + private readonly string PASSWORD_NORMALIZED; + private string serverNonce; + private string saltBase64; + private string clientFirstMsg; + private string serverFirstMsg; + + #endregion + //--------------------------------------------------------Constructor:----------------------------------------------------------------\\ + #region --Constructors-- + /// + /// Basic Constructor + /// + /// + /// 06/01/2019 Created [Fabian Sauter] + /// + public ScramSHA256SASLMechanism(string id, string password) : base(id, password) + { + } + + public ScramSHA256SASLMechanism(string id, string password, string clientNonceBase64) : base(id, password, clientNonceBase64) + { + } + + #endregion + //--------------------------------------------------------Set-, Get- Methods:---------------------------------------------------------\\ + #region --Set-, Get- Methods-- + + + #endregion + //--------------------------------------------------------Misc Methods:---------------------------------------------------------------\\ + #region --Misc Methods (Public)-- + public override SelectSASLMechanismMessage getSelectSASLMechanismMessage() + { + clientFirstMsg = "n=" + ID + ",r=" + CLIENT_NONCE_BASE_64; + string encClientFirstMsg = encodeStringBase64("n,," + clientFirstMsg); + + return new SelectSASLMechanismMessage("SCRAM-SHA-256", encClientFirstMsg); + } + + #endregion + + #region --Misc Methods (Private)-- + + #endregion + + #region --Misc Methods (Protected)-- + protected override bool isValidIterationsCount(int iters) + { + return iters >= 4096; + } + + #endregion + //--------------------------------------------------------Events:---------------------------------------------------------------------\\ + #region --Events-- + + + #endregion + } +} diff --git a/XMPP_API/Classes/Network/XML/Messages/Processor/SASLConnection.cs b/XMPP_API/Classes/Network/XML/Messages/Processor/SASLConnection.cs index 47fc88530..8b1e337cc 100644 --- a/XMPP_API/Classes/Network/XML/Messages/Processor/SASLConnection.cs +++ b/XMPP_API/Classes/Network/XML/Messages/Processor/SASLConnection.cs @@ -18,7 +18,7 @@ class SASLConnection : AbstractMessageProcessor private SASLState state; private AbstractSASLMechanism selectedMechanism; // The offered authentication mechanism in preferred order: - private static readonly ArrayList OFFERED_MECHANISMS = new ArrayList() { "scram-sha-1", "plain" }; + private static readonly ArrayList OFFERED_MECHANISMS = new ArrayList() { "scram-sha-256", "scram-sha-1", "plain" }; #endregion //--------------------------------------------------------Constructor:----------------------------------------------------------------\\ @@ -83,6 +83,10 @@ private void selectMechanism(ArrayList mechanisms) XMPPAccount sCC = XMPP_CONNECTION.account; switch (selected) { + case "scram-sha-256": + selectedMechanism = new ScramSHA256SASLMechanism(sCC.user.userId, sCC.user.userPassword); + break; + case "scram-sha-1": selectedMechanism = new ScramSHA1SASLMechanism(sCC.user.userId, sCC.user.userPassword); break; diff --git a/XMPP_API/XMPP_API.csproj b/XMPP_API/XMPP_API.csproj index eaf9d003a..6b8a3f3bc 100644 --- a/XMPP_API/XMPP_API.csproj +++ b/XMPP_API/XMPP_API.csproj @@ -159,6 +159,7 @@ +