Quellcode durchsuchen

ms BigInteger类由byte[]转换会产生负数,增加byte[]转换成unsign big integer功能

tanghai vor 13 Jahren
Ursprung
Commit
122f78dbad

+ 0 - 1
CSharp/App/Modules/Robot/Packages.config

@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
-  <package id="BouncyCastle" version="1.7.0" targetFramework="net45" />
   <package id="CommonServiceLocator" version="1.0" targetFramework="net45" />
   <package id="Prism" version="4.1.0.0" targetFramework="net45" />
   <package id="Prism.MEFExtensions" version="4.1.0.0" targetFramework="net45" />

+ 2 - 2
CSharp/App/Modules/Robot/Protos/Messages.cs

@@ -70,10 +70,10 @@ namespace Robot.Protos
 	public class CMSG_Auth_Logon_Permit
 	{
 		[DataMember(Order = 1, IsRequired = true)]
-		public string Account { get; set; }
+		public byte[] Account { get; set; }
 
 		[DataMember(Order = 2, IsRequired = true)]
-		public string PasswordMd5 { get; set; }
+		public byte[] PasswordMd5 { get; set; }
 	}
 
 	[DataContract]

+ 32 - 64
CSharp/App/Modules/Robot/RealmSession.cs

@@ -1,57 +1,27 @@
 using System;
-using System.Net;
+using System.Linq;
 using System.Net.Sockets;
+using System.Numerics;
 using System.Security.Cryptography;
 using System.Threading.Tasks;
 using Helper;
 using Log;
-using Org.BouncyCastle.Crypto.Agreement.Srp;
-using Org.BouncyCastle.Crypto.Digests;
-using Org.BouncyCastle.Math;
-using Org.BouncyCastle.Security;
-using Org.BouncyCastle.Utilities.Encoders;
 using Robot.Protos;
 
 namespace Robot
 {
 	public class RealmSession: IDisposable
 	{
-		private readonly NetworkStream networkStream;
+		private readonly TcpClient tcpClient = new TcpClient();
+		private NetworkStream networkStream;
 		private readonly RealmInfo realmInfo = new RealmInfo();
 
-		public RealmSession(string host, ushort port)
-		{
-			Socket socket = ConnectSocket(host, port);
-			this.networkStream = new NetworkStream(socket);
-		}
-
 		public void Dispose()
 		{
+			this.tcpClient.Close();
 			this.networkStream.Dispose();
 		}
 
-		public static Socket ConnectSocket(string host, ushort port)
-		{
-			IPHostEntry hostEntry = Dns.GetHostEntry(host);
-
-			foreach (IPAddress address in hostEntry.AddressList)
-			{
-				var ipe = new IPEndPoint(address, port);
-				var tempSocket = new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
-
-				tempSocket.Connect(ipe);
-
-				if (!tempSocket.Connected)
-				{
-					continue;
-				}
-
-				return tempSocket;
-			}
-			Logger.Debug("socket is null, address: {0}:{1}", host, port);
-			throw new SocketException(10000);
-		}
-
 		public async void SendMessage<T>(ushort opcode, T message)
 		{
 			byte[] protoBytes = ProtobufHelper.ToBytes(message);
@@ -168,21 +138,28 @@ namespace Robot
 			return new Tuple<ushort, byte[]>(opcode, messageBytes);
 		}
 
+		public async Task ConnectAsync(string hostName, ushort port)
+		{
+			await this.tcpClient.ConnectAsync(hostName, port);
+			this.networkStream = this.tcpClient.GetStream();
+		}
+
 		public async void Login(string account, string password)
 		{
 			byte[] passwordBytes = password.ToByteArray();
-			var digest = new MD5Digest();
-			var passwordMd5 = new byte[digest.GetDigestSize()];
-
-			digest.BlockUpdate(passwordBytes, 0, passwordBytes.Length);
-			digest.DoFinal(passwordMd5, 0);
+			MD5 md5 = MD5.Create();
+			byte[] passwordMd5 = md5.ComputeHash(passwordBytes);
 
 			// 发送帐号和密码MD5
 			var cmsgAuthLogonPermit = new CMSG_Auth_Logon_Permit
 			{ 
-				Account = account, 
-				PasswordMd5 = Hex.ToHexString(passwordMd5) 
+				Account = account.ToByteArray(),
+				PasswordMd5 = passwordMd5.ToHex().ToLower().ToByteArray()
 			};
+
+			Logger.Trace("account: {0}, password: {1}", 
+				cmsgAuthLogonPermit.Account, cmsgAuthLogonPermit.PasswordMd5.ToStr());
+
 			this.SendMessage(MessageOpcode.CMSG_AUTH_LOGON_PERMIT, cmsgAuthLogonPermit);
 			await this.Handle_CMSG_AuthLogonPermit_Response();
 
@@ -193,33 +170,24 @@ namespace Robot
 				await this.Handle_SMSG_Auth_Logon_Challenge_Response();
 
 			// 以下是SRP6处理过程
-			var random = new SecureRandom();
-			var srp6Client = new Srp6Client();
-			var n = new BigInteger(1, smsgAuthLogonChallengeResponse.N);
-			var g = new BigInteger(1, smsgAuthLogonChallengeResponse.G);
-			var s = new BigInteger(1, smsgAuthLogonChallengeResponse.S);
-			var b = new BigInteger(1, smsgAuthLogonChallengeResponse.B);
-			srp6Client.Init(n, g, new Sha1Digest(), random);
-			BigInteger a = srp6Client.GenerateClientCredentials(
-				s.ToByteArray(), account.ToByteArray(), password.ToByteArray());
-			BigInteger clientS = srp6Client.CalculateSecret(b);
-
-			var sha1Managed = new SHA1Managed();
-			byte[] k = SRP6Helper.SRP6ClientCalcK(sha1Managed, clientS.ToByteArray());
-			byte[] m = SRP6Helper.SRP6ClientM1(
-				sha1Managed, account.ToByteArray(), n.ToByteArray(), g.ToByteArray(), 
-				s.ToByteArray(), a.ToByteArray(), b.ToByteArray(), k);
+			var n = smsgAuthLogonChallengeResponse.N.ToUnsignedBigInteger();
+			var g = smsgAuthLogonChallengeResponse.G.ToUnsignedBigInteger();
+			var s = smsgAuthLogonChallengeResponse.S.ToUnsignedBigInteger();
+			var b = smsgAuthLogonChallengeResponse.B.ToUnsignedBigInteger();
+			string identity = account + ":" + password;
+
+			var srp6Client = new SRP6Client(new SHA1Managed(), n, g, b, s, identity, password);
 
 			Logger.Debug("N: {0}\nG: {1}\ns: {2}\nB: {3}\nA: {4}\nS: {5}\nK: {6}\nm: {7}",
-				smsgAuthLogonChallengeResponse.N.ToHex(), smsgAuthLogonChallengeResponse.G.ToHex(),
-				smsgAuthLogonChallengeResponse.S.ToHex(), smsgAuthLogonChallengeResponse.B.ToHex(),
-				a.ToByteArray().ToHex(), clientS.ToByteArray().ToHex(),
-				k.ToHex(), m.ToHex());
+				srp6Client.N.ToTrimByteArray().ToHex(), srp6Client.G.ToTrimByteArray().ToHex(),
+				srp6Client.S.ToTrimByteArray().ToHex(), srp6Client.B.ToTrimByteArray().ToHex(),
+				srp6Client.A.ToTrimByteArray().ToHex(), srp6Client.S.ToTrimByteArray().ToHex(),
+				srp6Client.K.ToTrimByteArray().ToHex(), srp6Client.M.ToHex());
 
 			var cmsgAuthLogonProof = new CMSG_Auth_Logon_Proof
 			{
-				A = a.ToByteArray(),
-				M = m
+				A = srp6Client.A.ToTrimByteArray(),
+				M = srp6Client.M
 			};
 			this.SendMessage(MessageOpcode.CMSG_AUTH_LOGON_PROOF, cmsgAuthLogonProof);
 		}

+ 2 - 4
CSharp/App/Modules/Robot/Robot.csproj

@@ -32,10 +32,6 @@
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
   <ItemGroup>
-    <Reference Include="BouncyCastle.Crypto, Version=1.7.4137.9283, Culture=neutral, PublicKeyToken=a4292a325f69b123, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\..\..\packages\BouncyCastle.1.7.0\lib\Net20\BouncyCastle.Crypto.dll</HintPath>
-    </Reference>
     <Reference Include="Microsoft.Practices.Prism">
       <HintPath>..\..\..\packages\Prism.4.1.0.0\lib\NET40\Microsoft.Practices.Prism.dll</HintPath>
     </Reference>
@@ -47,6 +43,7 @@
     <Reference Include="System" />
     <Reference Include="System.ComponentModel.Composition" />
     <Reference Include="System.Core" />
+    <Reference Include="System.Numerics" />
     <Reference Include="System.Runtime.Serialization" />
     <Reference Include="System.Xaml" />
     <Reference Include="System.Xml" />
@@ -63,6 +60,7 @@
     <Compile Include="RobotView.xaml.cs">
       <DependentUpon>RobotView.xaml</DependentUpon>
     </Compile>
+    <Compile Include="SRP6Client.cs" />
   </ItemGroup>
   <ItemGroup>
     <Page Include="RobotView.xaml">

+ 4 - 4
CSharp/App/Modules/Robot/RobotViewModel.cs

@@ -34,7 +34,7 @@ namespace Modules.Robot
 					return;
 				}
 				this.loginIP = value;
-				this.RaisePropertyChanged("LoginIp");
+				this.RaisePropertyChanged("LoginIP");
 			}
 		}
 
@@ -113,12 +113,12 @@ namespace Modules.Robot
 			this.clientHost.Dispose();
 		}
 
-		public void Login()
+		public async void Login()
 		{
-			var session = new RealmSession(this.LoginIP, this.LoginPort);
-
 			try
 			{
+				var session = new RealmSession();
+				await session.ConnectAsync(this.LoginIP, this.LoginPort);
 				session.Login(this.Account, this.Password);
 			}
 			catch (Exception e)

+ 246 - 0
CSharp/App/Modules/Robot/SRP6Client.cs

@@ -0,0 +1,246 @@
+using System;
+using System.Globalization;
+using System.Linq;
+using System.Numerics;
+using System.Security.Cryptography;
+using Helper;
+
+namespace Robot
+{
+	public class SRP6Client
+	{
+		private readonly BigInteger n;    // N
+		private readonly BigInteger g;    // g
+		private readonly BigInteger b;    // B
+		private readonly BigInteger a;    // A
+		private readonly BigInteger x;    // X
+		private readonly BigInteger u;    // U
+		private readonly BigInteger s;    // S
+		private readonly BigInteger k;    // K
+		private readonly byte[] m;        // M
+		private readonly byte[] p;
+		private readonly string account;
+		private readonly BigInteger salt; // s, 服务端发过来的salt
+		private const int lowerK = 3;
+		private readonly HashAlgorithm hashAlgorithm;
+
+		public SRP6Client(
+			HashAlgorithm hashAlgorithm, BigInteger n, BigInteger g, BigInteger b,
+			BigInteger salt, string account, string password)
+		{
+			this.hashAlgorithm = hashAlgorithm;
+			this.n = n;
+			this.g = g;
+			this.b = b;
+			this.salt = salt;
+			this.account = account;
+			string identity = account + ":" + password;
+			this.p = hashAlgorithm.ComputeHash(identity.ToByteArray());
+			this.a = this.CalculateA();  // A = g ^ a % N
+			this.x = this.CalculateX();  // X = H(s, P)
+			this.u = this.CalculateU();  // U = H(A, B)
+			this.s = this.CalculateS();  // S = (B - (k * g.ModExp(x, N))).ModExp(a + (u * x), N)
+			this.k = this.CalculateK();
+			this.m = this.CalculateM();  // 
+		}
+
+		public BigInteger N
+		{
+			get
+			{
+				return this.n;
+			}
+		}
+
+		public BigInteger G
+		{
+			get
+			{
+				return this.g;
+			}
+		}
+
+		public BigInteger B
+		{
+			get
+			{
+				return this.b;
+			}
+		}
+
+		public BigInteger A
+		{
+			get
+			{
+				return this.a;
+			}
+		}
+
+		public BigInteger X
+		{
+			get
+			{
+				return this.x;
+			}
+		}
+
+		public BigInteger U
+		{
+			get
+			{
+				return this.u;
+			}
+		}
+
+		public BigInteger S
+		{
+			get
+			{
+				return this.s;
+			}
+		}
+
+		public BigInteger K
+		{
+			get
+			{
+				return this.k;
+			}
+		}
+
+		public byte[] M
+		{
+			get
+			{
+				return this.m;
+			}
+		}
+
+		public byte[] P
+		{
+			get
+			{
+				return this.p;
+			}
+		}
+
+		/// <summary>
+		/// 计算X: X = H(s, P)
+		/// </summary>
+		/// <returns></returns>
+		private BigInteger CalculateX()
+		{
+			hashAlgorithm.Initialize();
+			var joinBytes = new byte[0]
+				.Concat(salt.ToTrimByteArray())
+				.Concat(this.P)
+				.ToArray();
+			return hashAlgorithm.ComputeHash(joinBytes).ToUnsignedBigInteger();
+		}
+
+		/// <summary>
+		/// 计算A: A = g ^ a % N
+		/// </summary>
+		/// <returns></returns>
+		private BigInteger CalculateA()
+		{
+			BigInteger randomA = BigIntegerHelper.RandUnsignedBigInteger(19);
+			BigInteger calculatA = BigInteger.ModPow(this.G, randomA, this.N);
+			return calculatA;
+		}
+
+		/// <summary>
+		/// 计算U: U = H(A, B)
+		/// </summary>
+		/// <returns></returns>
+		private BigInteger CalculateU()
+		{
+			hashAlgorithm.Initialize();
+			var joinBytes = new byte[0]
+				.Concat(this.A.ToTrimByteArray())
+				.Concat(this.B.ToTrimByteArray())
+				.ToArray();
+			return hashAlgorithm.ComputeHash(joinBytes).ToUnsignedBigInteger();
+		}
+
+		/// <summary>
+		/// 计算S: S = (B - (k * g.ModExp(x, N))).ModExp(a + (u * x), N);
+		/// </summary>
+		/// <returns></returns>
+		private BigInteger CalculateS()
+		{
+			BigInteger s1 = this.B - BigInteger.ModPow(this.G, this.X, this.N) * lowerK;
+			BigInteger s2 = this.A + (this.U * this.X);
+			return BigInteger.ModPow(s1, s2, this.N);
+		}
+
+		/// <summary>
+		/// 
+		/// </summary>
+		/// <returns></returns>
+		private BigInteger CalculateK()
+		{
+			hashAlgorithm.Initialize();
+			byte[] sBytes = this.S.ToTrimByteArray();
+			int sLength = sBytes.Length;
+			int halfLength = sLength / 2;
+			var kBytes = new byte[40];
+			var halfS = new byte[sLength];
+
+			for (int i = 0; i < halfLength; ++i)
+			{
+				halfS[i] = sBytes[i * 2];
+			}
+			var p1 = hashAlgorithm.ComputeHash(halfS);
+			for (int i = 0; i < 20; ++i)
+			{
+				kBytes[i * 2] = p1[i];
+			}
+
+			for (int i = 0; i < halfLength; ++i)
+			{
+				halfS[i] = sBytes[i * 2 + 1];
+			}
+			var p2 = hashAlgorithm.ComputeHash(halfS);
+			for (int i = 0; i < 20; ++i)
+			{
+				kBytes[i * 2 + 1] = p2[i];
+			}
+
+			return kBytes.ToUnsignedBigInteger();
+		}
+
+		/// <summary>
+		/// 
+		/// </summary>
+		/// <returns></returns>
+		private Byte[] CalculateM()
+		{
+			hashAlgorithm.Initialize();
+			var hashN = hashAlgorithm.ComputeHash(this.N.ToTrimByteArray());
+			var hashG = hashAlgorithm.ComputeHash(this.G.ToTrimByteArray());
+
+			// 这里与标准srp6不一样,只异或了20个byte,实际上有32个byte
+			for (var i = 0; i < 20; ++i)
+			{
+				hashN[i] ^= hashG[i];
+			}
+
+			var hashGXorhashN = hashN; // H(N) ^ H(g)
+			var hashedIdentity = hashAlgorithm.ComputeHash(this.account.ToByteArray()); // H(I)
+
+			// H(H(N) ^ H(g), H(P), s, A, B, K_c)
+			var calculateM = hashAlgorithm.ComputeHash(new byte[0]
+				.Concat(hashGXorhashN)
+				.Concat(hashedIdentity)
+				.Concat(this.salt.ToTrimByteArray())
+				.Concat(this.A.ToTrimByteArray())
+				.Concat(this.B.ToTrimByteArray())
+				.Concat(this.K.ToTrimByteArray())
+				.ToArray());
+			var copyM = new byte[20];
+			Array.Copy(calculateM, copyM, copyM.Length);
+			return calculateM;
+		}
+	}
+}

+ 47 - 0
CSharp/Platform/Helper/BigIntegerHelper.cs

@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Numerics;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Helper
+{
+	public static class BigIntegerHelper
+	{
+		public static BigInteger RandBigInteger(int byteNum)
+		{
+			var bigIntegerBytes = new byte[byteNum];
+			var random = new Random();
+			random.NextBytes(bigIntegerBytes);
+			var bigInteger = new BigInteger(bigIntegerBytes);
+			return bigInteger;
+		}
+
+		public static BigInteger RandUnsignedBigInteger(int byteNum)
+		{
+			var bigIntegerBytes = new byte[byteNum];
+			var random = new Random();
+			random.NextBytes(bigIntegerBytes);
+
+			var newBigIntegerBytes = new byte[byteNum + 1];
+
+			// 给最高位加个0,防止变成负数
+			Array.Copy(bigIntegerBytes, newBigIntegerBytes, bigIntegerBytes.Length);
+			newBigIntegerBytes[newBigIntegerBytes.Length - 1] = 0;
+
+			var bigInteger = new BigInteger(newBigIntegerBytes);
+			return bigInteger;
+		}
+
+		public static byte[] ToTrimByteArray(this BigInteger bigInteger)
+		{
+			var bytes = bigInteger.ToByteArray();
+			if (bytes[bytes.Length - 1] == 0)
+			{
+				return bytes.Take(bytes.Length - 1).ToArray();
+			}
+			return bytes;
+		}
+	}
+}

+ 13 - 0
CSharp/Platform/Helper/ByteHelper.cs

@@ -1,5 +1,7 @@
 using System.Collections.Generic;
 using System.Globalization;
+using System.Linq;
+using System.Numerics;
 using System.Text;
 
 namespace Helper
@@ -30,5 +32,16 @@ namespace Helper
 			}
 			return stringBuilder.ToString();
 		}
+
+		public static BigInteger ToUnsignedBigInteger(this byte[] bytes)
+		{
+			bytes = bytes.Concat(new[] { (byte)'0' }).ToArray();
+			return new BigInteger(bytes);
+		}
+
+		public static BigInteger ToBigInteger(this byte[] bytes)
+		{
+			return new BigInteger(bytes);
+		}
 	}
 }

+ 2 - 5
CSharp/Platform/Helper/Helper.csproj

@@ -32,22 +32,19 @@
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
   <ItemGroup>
-    <Reference Include="BouncyCastle.Crypto, Version=1.7.4137.9283, Culture=neutral, PublicKeyToken=a4292a325f69b123, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\..\packages\BouncyCastle.1.7.0\lib\Net20\BouncyCastle.Crypto.dll</HintPath>
-    </Reference>
     <Reference Include="protobuf-net, Version=2.0.0.621, Culture=neutral, PublicKeyToken=257b51d87d2e4d67, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
       <HintPath>..\..\packages\protobuf-net.2.0.0.621\lib\net40\protobuf-net.dll</HintPath>
     </Reference>
     <Reference Include="System" />
     <Reference Include="System.Core" />
+    <Reference Include="System.Numerics" />
     <Reference Include="System.Runtime.Serialization" />
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
     <Compile Include="ByteHelper.cs" />
-    <Compile Include="SRP6Helper.cs" />
+    <Compile Include="BigIntegerHelper.cs" />
     <Compile Include="JsonHelper.cs" />
     <Compile Include="LoaderHelper.cs" />
     <Compile Include="ProtobufHelper.cs" />

+ 0 - 1
CSharp/Platform/Helper/Packages.config

@@ -1,5 +1,4 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
-  <package id="BouncyCastle" version="1.7.0" targetFramework="net45" />
   <package id="protobuf-net" version="2.0.0.621" targetFramework="net45" />
 </packages>

+ 0 - 68
CSharp/Platform/Helper/SRP6Helper.cs

@@ -1,68 +0,0 @@
-using System.Linq;
-using System.Security.Cryptography;
-
-namespace Helper
-{
-	public static class SRP6Helper
-	{
-		public static byte[] SRP6ClientCalcK(HashAlgorithm hashAlgorithm, byte[] clientS)
-		{
-			int clientSLength = clientS.Length;
-			int halfLength = clientSLength / 2;
-			var kBytes = new byte[40];
-			var halfS = new byte[clientSLength];
-
-			for (int i = 0; i < halfLength; ++i)
-			{
-				halfS[i] = clientS[i * 2];
-			}
-
-			var p1 = hashAlgorithm.ComputeHash(halfS);
-			for (int i = 0; i < 20; ++i)
-			{
-				kBytes[i * 2] = p1[i];
-			}
-
-			for (int i = 0; i < halfLength; ++i)
-			{
-				halfS[i] = clientS[i * 2 + 1];
-			}
-
-			var p2 = hashAlgorithm.ComputeHash(halfS);
-			for (int i = 0; i < 20; ++i)
-			{
-				kBytes[i * 2 + 1] = p2[i];
-			}
-
-			return kBytes;
-		}
-
-		public static byte[] SRP6ClientM1(
-			HashAlgorithm hashAlgorithm, byte[] identitySalt,
-			byte[] n, byte[] g, byte[] s, byte[] a,
-			byte[] b, byte[] k)
-		{
-			var hashN = hashAlgorithm.ComputeHash(n);
-			var hashG = hashAlgorithm.ComputeHash(g);
-			for (var i = 0; i < hashN.Length; ++i)
-			{
-				hashN[i] ^= hashG[i];
-			}
-
-			var hashGXorhashN = hashN; // H(N) ^ H(g)
-			var hashedIdentitySalt = hashAlgorithm.ComputeHash(identitySalt); // H(I)
-
-			// H(H(N) ^ H(g), H(I), s, A, B, K_c)
-			var m = hashAlgorithm.ComputeHash(new byte[0] 
-				.Concat(hashGXorhashN)
-				.Concat(hashedIdentitySalt)
-				.Concat(s)
-				.Concat(a)
-				.Concat(b)
-				.Concat(k)
-				.ToArray());
-
-			return m;
-		}
-	}
-}