/// <summary> /// Generates a proper hash for old style 4.1.0 passwords. This would be used /// if a 4.1.0 server contained old 16 byte hashes. /// </summary> /// <param name="password">The password to hash</param> /// <param name="seedBytes">Seed bytes received from the server</param> /// <returns>Byte array containing the password hash</returns> public static byte[] GetOld410Password(string password, byte[] seedBytes) { long[] passwordHash = Hash(password); string passHex = String.Format(CultureInfo.InvariantCulture, "{0,8:X}{1,8:X}", passwordHash[0], passwordHash[1]); int[] salt = getSaltFromPassword(passHex); // compute binary password byte[] binaryPassword = new byte[20]; int offset = 0; for (int i = 0; i < 2; i++) { int val = salt[i]; for (int t = 3; t >= 0; t--) { binaryPassword[t + offset] = (byte) (val%256); val >>= 8; /* Scroll 8 bits to get next part*/ } offset += 4; } //SHA1 sha = new SHA1CryptoServiceProvider(); SHA1Hash sha = new SHA1Hash(); byte[] temp = new byte[8]; Buffer.BlockCopy(binaryPassword, 0, temp, 0, 8); byte[] binaryHash = sha.ComputeHash(temp); byte[] scrambledBuff = new byte[20]; XorScramble(seedBytes, 4, scrambledBuff, 0, binaryHash, 20); string scrambleString = Encoding.Default.GetString(scrambledBuff, 0, scrambledBuff.Length).Substring(0, 8); long[] hashPass = Hash(password); long[] hashMessage = Hash(scrambleString); long max = 0x3FFFFFFFL; byte[] to = new byte[20]; int msgPos = 0; int msgLength = scrambleString.Length; int toPos = 0; long seed1 = (hashPass[0] ^ hashMessage[0])%max; long seed2 = (hashPass[1] ^ hashMessage[1])%max; while (msgPos++ < msgLength) to[toPos++] = (byte) (Math.Floor(rand(ref seed1, ref seed2, max)*31) + 64); /* Make it harder to break */ byte extra = (byte) (Math.Floor(rand(ref seed1, ref seed2, max)*31)); for (int i = 0; i < 8; i++) to[i] ^= extra; return to; }
/// <summary> /// Generate a scrambled password for 4.1.0 using new passwords /// </summary> /// <param name="password">The password to scramble</param> /// <param name="seedBytes">The seedbytes used to scramble</param> /// <returns>Array of bytes containing the scrambled password</returns> public static byte[] Get410Password(string password, byte[] seedBytes) { SHA1Hash sha = new SHA1Hash(); //SHA1 sha = new SHA1CryptoServiceProvider(); // clean it and then digest it password = password.Replace(" ", "").Replace("\t", ""); byte[] passBytes = Encoding.Default.GetBytes(password); byte[] firstPass = sha.ComputeHash(passBytes); byte[] input = new byte[24]; Array.Copy(seedBytes, 0, input, 0, 4); Array.Copy(firstPass, 0, input, 4, 20); byte[] secondPass = sha.ComputeHash(input); byte[] scrambledBuff = new byte[20]; XorScramble(seedBytes, 4, scrambledBuff, 0, secondPass, 20); byte[] finalBuff = new byte[20]; XorScramble(scrambledBuff, 0, finalBuff, 0, firstPass, 20); return finalBuff; }
/// <summary> /// Returns a byte array containing the proper encryption of the /// given password/seed according to the new 4.1.1 authentication scheme. /// </summary> /// <param name="password"></param> /// <param name="seed"></param> /// <returns></returns> public static byte[] Get411Password(string password, string seed) { // if we have no password, then we just return 1 zero byte if (password.Length == 0) return new byte[1]; //SHA1 sha = new SHA1CryptoServiceProvider(); SHA1Hash sha = new SHA1Hash(); byte[] firstHash = sha.ComputeHash(Encoding.Default.GetBytes(password)); byte[] secondHash = sha.ComputeHash(firstHash); byte[] seedBytes = Encoding.Default.GetBytes(seed); byte[] input = new byte[seedBytes.Length + secondHash.Length]; Array.Copy(seedBytes, 0, input, 0, seedBytes.Length); Array.Copy(secondHash, 0, input, seedBytes.Length, secondHash.Length); byte[] thirdHash = sha.ComputeHash(input); byte[] finalHash = new byte[thirdHash.Length + 1]; finalHash[0] = 0x14; Array.Copy(thirdHash, 0, finalHash, 1, thirdHash.Length); for (int i = 1; i < finalHash.Length; i++) finalHash[i] = (byte) (finalHash[i] ^ firstHash[i - 1]); return finalHash; }
/// <summary> /// Returns a byte array containing the proper encryption of the /// given password/seed according to the new 4.1.1 authentication scheme. /// </summary> /// <param name="password"></param> /// <param name="seed"></param> /// <returns></returns> public static byte[] Get411Password(string password, string seed) { // if we have no password, then we just return 2 zero bytes if (password.Length == 0) return new byte[1]; var sha = new SHA1Hash(); byte[] firstHash = sha.ComputeHash(Encoding.UTF8.GetBytes(password)); byte[] secondHash = sha.ComputeHash(firstHash); byte[] seedBytes = Encoding.UTF8.GetBytes(seed); byte[] input = new byte[seedBytes.Length + secondHash.Length]; Array.Copy(seedBytes, 0, input, 0, seedBytes.Length); Array.Copy(secondHash, 0, input, seedBytes.Length, secondHash.Length); byte[] thirdHash = sha.ComputeHash(input); byte[] finalHash = new byte[thirdHash.Length + 1]; finalHash[0] = 0x14; Array.Copy(thirdHash, 0, finalHash, 1, thirdHash.Length); for (int i = 1; i < finalHash.Length; i++) finalHash[i] = (byte)(finalHash[i] ^ firstHash[i - 1]); return finalHash; //byte[] buffer = new byte[finalHash.Length - 1]; //Array.Copy(finalHash, 1, buffer, 0, finalHash.Length - 1); //return buffer; }