www.pudn.com > boogiebot.zip > Srp6.cs


/* 
 * Copyright ¸ 2005 Kele (fooleau@gmail.com) 
 * This library is free software; you can redistribute it and/or  
 * modify it under the terms of the GNU Lesser General Public  
 * License version 2.1 as published by the Free Software Foundation 
 * (the "LGPL"). 
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY 
 * OF ANY KIND, either express or implied. 
 */ 
 
using System; 
 
namespace Foole.Crypt 
{ 
	///  
	/// Description of SRP6. 
	///  
	public class Srp6 
	{ 
		BigInteger N; 
		BigInteger g; 
		BigInteger k = new BigInteger(3); 
 
		public Srp6(BigInteger N, BigInteger g) 
		{ 
			this.N = N; 
			this.g = g; 
		} 
 
		public static byte[] GetLogonHash(string Username, string Password) 
		{ 
			Sha1Hash h = new Sha1Hash(); 
			string sI = String.Format("{0}:{1}", Username, Password.ToUpper()); 
			h.Update(sI); 
			return h.Final(); 
		} 
 
		public static BigInteger Getx(BigInteger Salt, byte[] LogonHash) 
		{ 
			Sha1Hash h = new Sha1Hash(); 
			h.Update(Salt); 
            h.Update(LogonHash); 
			return new BigInteger(h.Final()); 
		} 
		 
		public BigInteger GetA(BigInteger a) 
		{ 
			return g.modPow(a, N); 
		} 
 
		public BigInteger GetB(BigInteger b, BigInteger v) 
		{ 
			BigInteger B = ((v * k) + g.modPow(b, N)) % N; 
			return B; 
		} 
 
		public BigInteger Getv(BigInteger x) 
		{ 
			return g.modPow(x, N); 
		} 
 
		// HandleLogonProof stuff 
		public static BigInteger Getu(BigInteger A, BigInteger B) 
		{ 
			Sha1Hash h = new Sha1Hash(); 
			h.Update(A); 
			return new BigInteger(h.Final(B)); 
		} 
 
		// Server version 
		// S = (Av^u) ^ b 
		public BigInteger ServerGetS(BigInteger A, BigInteger b, BigInteger v, BigInteger u) 
		{ 
			return (A * (v.modPow(u, N))).modPow(b, N); 
		} 
 
		// Client version 
		// S = (B - kg^x) ^ (a + ux) 
		public BigInteger ClientGetS(BigInteger a, BigInteger B, BigInteger x, BigInteger u) 
		{ 
			BigInteger S; 
			S = (B - (k * g.modPow(x, N))).modPow(a + (u * x), N); 
			return S; 
		} 
 
		public BigInteger GetM(string Username, BigInteger s, BigInteger A, BigInteger B, BigInteger K) 
		{ 
			Sha1Hash sha; 
			 
			sha = new Sha1Hash(); 
			byte[] hash = sha.Final(N); 
 
			sha = new Sha1Hash(); 
			byte[] ghash = sha.Final(g); 
 
			for (int i = 0; i < 20; ++i) 
				hash[i] ^= ghash[i]; 
 
			// TODO: do t2 and t4 need to be BigInts?  Could we just use the byte[]? 
			BigInteger t3 = new BigInteger(hash); 
 
			sha = new Sha1Hash(); 
			sha.Update(Username); 
			BigInteger t4 = new BigInteger(sha.Final()); 
 
			sha = new Sha1Hash(); 
			sha.Update(t3); 
			sha.Update(t4); 
			sha.Update(s); 
			sha.Update(A); 
			sha.Update(B); 
			return new BigInteger(sha.Final(K)); 
		} 
 
		public static byte[] GetM2(BigInteger A, BigInteger M, BigInteger K) 
		{ 
			Sha1Hash h = new Sha1Hash(); 
			h.Update(A); 
			h.Update(M); 
			return h.Final(K); 
		} 
 
		// Converts S to K 
		// K is the Key which is passed to the Crypt class 
		public static byte[] ShaInterleave(BigInteger S) 
		{ 
			byte[] t = S; 
			int HalfSize = t.Length / 2; // Untested.  I previously hard coded this as 16 
			byte[] t1 = new byte[HalfSize]; 
			 
			for (int i = 0; i < HalfSize; i++) 
				t1[i] = t[i*2]; 
				 
			Sha1Hash sha = new Sha1Hash(); 
			byte[] t1hash = sha.Final(t1); 
 
			byte[] vK = new byte[40]; 
			for (int i = 0; i < 20; i++) 
				vK[i*2] = t1hash[i]; 
				 
			for (int i = 0; i < HalfSize; i++) 
				t1[i] = t[i*2+1]; 
 
			sha = new Sha1Hash(); 
			t1hash = sha.Final(t1); 
 
			for (int i = 0; i < 20; i++) 
				vK[i*2+1] = t1hash[i]; 
 
			return vK; 
		} 
	} 
}