TSforge/LibTSforge/SPP/ProductKey.cs

314 lines
9.6 KiB
C#
Raw Permalink Normal View History

namespace LibTSforge.SPP
{
using System;
using System.IO;
using System.Linq;
using LibTSforge.Crypto;
using LibTSforge.PhysicalStore;
public class ProductKey
{
private static readonly string ALPHABET = "BCDFGHJKMPQRTVWXY2346789";
private readonly ulong klow;
private readonly ulong khigh;
public int Group;
public int Serial;
public ulong Security;
public bool Upgrade;
public PKeyAlgorithm Algorithm;
public string EulaType;
public string PartNumber;
public string Edition;
public string Channel;
public Guid ActivationId;
private string mpc;
private string pid2;
public byte[] KeyBytes
{
get { return BitConverter.GetBytes(klow).Concat(BitConverter.GetBytes(khigh)).ToArray(); }
}
public ProductKey(int serial, ulong security, bool upgrade, PKeyAlgorithm algorithm, ProductConfig config, KeyRange range)
{
Group = config.GroupId;
Serial = serial;
Security = security;
Upgrade = upgrade;
Algorithm = algorithm;
EulaType = range.EulaType;
PartNumber = range.PartNumber.Split(':', ';')[0];
Edition = config.Edition;
Channel = config.Channel;
ActivationId = config.ActivationId;
klow = ((security & 0x3fff) << 50 | ((ulong)serial & 0x3fffffff) << 20 | ((ulong)Group & 0xfffff));
khigh = ((upgrade ? (ulong)1 : 0) << 49 | ((security >> 14) & 0x7fffffffff));
uint checksum = Utils.CRC32(KeyBytes) & 0x3ff;
khigh |= ((ulong)checksum << 39);
}
public string GetAlgoUri()
{
return "msft:rm/algorithm/pkey/" + (Algorithm == PKeyAlgorithm.PKEY2005 ? "2005" : (Algorithm == PKeyAlgorithm.PKEY2009 ? "2009" : "Unknown"));
}
public Guid GetPkeyId()
{
VariableBag pkb = new VariableBag();
pkb.Blocks.AddRange(new CRCBlock[]
{
new CRCBlock
{
DataType = CRCBlockType.STRING,
KeyAsStr = "SppPkeyBindingProductKey",
ValueAsStr = ToString()
},
new CRCBlock
{
DataType = CRCBlockType.BINARY,
KeyAsStr = "SppPkeyBindingMiscData",
Value = new byte[] { }
},
new CRCBlock
{
DataType = CRCBlockType.STRING,
KeyAsStr = "SppPkeyBindingAlgorithm",
ValueAsStr = GetAlgoUri()
}
});
return new Guid(CryptoUtils.SHA256Hash(pkb.Serialize()).Take(16).ToArray());
}
public string GetDefaultMPC()
{
int build = Environment.OSVersion.Version.Build;
string defaultMPC = build >= 10240 ? "03612" :
build >= 9600 ? "06401" :
build >= 9200 ? "05426" :
"55041";
return defaultMPC;
}
public string GetMPC()
{
if (mpc != null)
{
return mpc;
}
mpc = GetDefaultMPC();
// setup.cfg doesn't exist in Windows 8+
string setupcfg = string.Format("{0}\\oobe\\{1}", Environment.SystemDirectory, "setup.cfg");
if (!File.Exists(setupcfg) || Edition.Contains(";"))
{
return mpc;
}
string mpcKey = string.Format("{0}.{1}=", Utils.GetArchitecture(), Edition);
string localMPC = File.ReadAllLines(setupcfg).FirstOrDefault(line => line.Contains(mpcKey));
if (localMPC != null)
{
mpc = localMPC.Split('=')[1].Trim();
}
return mpc;
}
public string GetPid2()
{
if (pid2 != null)
{
return pid2;
}
pid2 = "";
if (Algorithm == PKeyAlgorithm.PKEY2005)
{
string mpc = GetMPC();
string serialHigh;
int serialLow;
int lastPart;
if (EulaType == "OEM")
{
serialHigh = "OEM";
serialLow = ((Group / 2) % 100) * 10000 + (Serial / 100000);
lastPart = Serial % 100000;
}
else
{
serialHigh = (Serial / 1000000).ToString("D3");
serialLow = Serial % 1000000;
lastPart = ((Group / 2) % 100) * 1000 + new Random().Next(1000);
}
int checksum = 0;
foreach (char c in serialLow.ToString())
{
checksum += int.Parse(c.ToString());
}
checksum = 7 - (checksum % 7);
pid2 = string.Format("{0}-{1}-{2:D6}{3}-{4:D5}", mpc, serialHigh, serialLow, checksum, lastPart);
}
return pid2;
}
public byte[] GetPid3()
{
BinaryWriter writer = new BinaryWriter(new MemoryStream());
writer.Write(0xA4);
writer.Write(0x3);
writer.WriteFixedString(GetPid2(), 24);
writer.Write(Group);
writer.WriteFixedString(PartNumber, 16);
writer.WritePadding(0x6C);
byte[] data = writer.GetBytes();
byte[] crc = BitConverter.GetBytes(~Utils.CRC32(data.Reverse().ToArray())).Reverse().ToArray();
writer.Write(crc);
return writer.GetBytes();
}
public byte[] GetPid4()
{
BinaryWriter writer = new BinaryWriter(new MemoryStream());
writer.Write(0x4F8);
writer.Write(0x4);
writer.WriteFixedString16(GetExtendedPid(), 0x80);
writer.WriteFixedString16(ActivationId.ToString(), 0x80);
writer.WritePadding(0x10);
writer.WriteFixedString16(Edition, 0x208);
writer.Write(Upgrade ? (ulong)1 : 0);
writer.WritePadding(0x50);
writer.WriteFixedString16(PartNumber, 0x80);
writer.WriteFixedString16(Channel, 0x80);
writer.WriteFixedString16(EulaType, 0x80);
return writer.GetBytes();
}
public string GetExtendedPid()
{
string mpc = GetMPC();
int serialHigh = Serial / 1000000;
int serialLow = Serial % 1000000;
int licenseType;
uint lcid = Utils.GetSystemDefaultLCID();
int build = Environment.OSVersion.Version.Build;
int dayOfYear = DateTime.Now.DayOfYear;
int year = DateTime.Now.Year;
switch (EulaType)
{
case "OEM":
licenseType = 2;
break;
case "Volume":
licenseType = 3;
break;
default:
licenseType = 0;
break;
}
return string.Format(
"{0}-{1:D5}-{2:D3}-{3:D6}-{4:D2}-{5:D4}-{6:D4}.0000-{7:D3}{8:D4}",
mpc,
Group,
serialHigh,
serialLow,
licenseType,
lcid,
build,
dayOfYear,
year
);
}
public byte[] GetPhoneData(PSVersion version)
{
if (version == PSVersion.Win7)
{
Random rnd = new Random(Group * 1000000000 + Serial);
byte[] data = new byte[8];
rnd.NextBytes(data);
return data;
}
int serialHigh = Serial / 1000000;
int serialLow = Serial % 1000000;
BinaryWriter writer = new BinaryWriter(new MemoryStream());
writer.Write(new Guid("B8731595-A2F6-430B-A799-FBFFB81A8D73").ToByteArray());
writer.Write(Group);
writer.Write(serialHigh);
writer.Write(serialLow);
writer.Write(Upgrade ? 1 : 0);
writer.Write(Security);
return writer.GetBytes();
}
public override string ToString()
{
string keyStr = "";
Random rnd = new Random(Group * 1000000000 + Serial);
if (Algorithm == PKeyAlgorithm.PKEY2005)
{
keyStr = "H4X3DH4X3DH4X3DH4X3D";
for (int i = 0; i < 5; i++)
{
keyStr += ALPHABET[rnd.Next(24)];
}
}
else if (Algorithm == PKeyAlgorithm.PKEY2009)
{
int last = 0;
byte[] bKey = KeyBytes;
for (int i = 24; i >= 0; i--)
{
int current = 0;
for (int j = 14; j >= 0; j--)
{
current *= 0x100;
current += bKey[j];
bKey[j] = (byte)(current / 24);
current %= 24;
last = current;
}
keyStr = ALPHABET[current] + keyStr;
}
keyStr = keyStr.Substring(1, last) + "N" + keyStr.Substring(last + 1, keyStr.Length - last - 1);
}
for (int i = 5; i < keyStr.Length; i += 6)
{
keyStr = keyStr.Insert(i, "-");
}
return keyStr;
}
}
}