[Serializable]的应用--注册码的生成,加密和验证
1.首先定义注册类RegisterEntity
[Serializable]
public class RegisterEntity
{
public string RegisterKey;
public bool IsRegistered;
public List<int> RegisterOrder;
public DateTime RegisterDate;
public DateTime ExpireDate;
}
RegisterKey,注册码(序列号)
IsRegistered,是否已注册
RegisterOrder,注册顺序,由于打开注册码生成文件的时候会暴露Guid,这里作了一个简单的加密算法,打乱顺序后存入RegisterKey,而打乱后的顺序会存入这个List,
RegisterDate,注册日期
ExpireDate,过期日期
2.生成序列号
private RegisterEntity GenerateRegisterKey(RegisterEntity registerEntity)
{
StringBuilder fakeKey = new StringBuilder();
string keyPart;
List<int> registerOrder = new List<int>();
int splitCount = 4;
int currentOrder = 0;
for (int i = 0; i < splitCount; i++)
{
keyPart = Guid.NewGuid().ToString().Substring(0, 6).ToUpper();
currentOrder = new Random().Next(1, splitCount + 1);
while (registerOrder.Contains(currentOrder - 1))
{
Thread.Sleep(100);
currentOrder = new Random().Next(1, splitCount + 1);
}
registerOrder.Add(currentOrder - 1);
keyPart += "-";
fakeKey.Append(keyPart);
}
fakeKey.Remove(fakeKey.Length - 1, 1);
message = fakeKey.ToString();
registerEntity.RegisterOrder = registerOrder;
return registerEntity;
}
这里随机生成了4个六位的Guid,用三个“-”连接起来就是序列号的格式了,打乱顺序用了Random方法,这样顺序也就只有电脑知道了,如果想复杂点可以把splitCount设置大一点,甚至可以把24个字母全部打乱,也就比较难破解了
3.加密
private string EncipherRegisterKey(RegisterEntity registerEntity)
{
string[] fakeKeyArgs = message.Split('-');
string[] realKeyArgs = new string[4];
for (int i = 0; i < fakeKeyArgs.Length; i++)
{
realKeyArgs[registerEntity.RegisterOrder[i]] = fakeKeyArgs[i];
}
StringBuilder realKey = new StringBuilder();
string keyPart = string.Empty;
for (int i = 0; i < realKeyArgs.Length; i++)
{
keyPart = realKeyArgs[i].ToString() + "-";
realKey.Append(keyPart);
}
realKey.Remove(realKey.Length - 1, 1);
return realKey.ToString();
}
实际上加密应该包括第2步,这里只是把序列号按照随机打乱的顺序重新组合了一下
4.把生成的Key写入文件
public string GenerateRegisterKeyToBinFile(string registerFileName)
{
message = string.Empty;
try
{
registerEntity = new RegisterEntity();
GenerateRegisterKey(registerEntity);
// encipher 加密
registerEntity.RegisterKey = EncipherRegisterKey(registerEntity);
registerEntity.IsRegistered = false;
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream(registerFileName, FileMode.Create,
FileAccess.Write, FileShare.None);
formatter.Serialize(stream, registerEntity);
stream.Close();
}
catch (Exception ex)
{
message = "Error: " + ex.Message;
return message;
}
return message;
}
在这里,每次生成新Key的时候由于会覆盖旧文件,而验证的时候是读取Key文件进行比对,所以在这里把IsRegistered设成了false
5.解密
private string DecipherRegisterKey(RegisterEntity registerEntity)
{
string[] realKeyArgs = registerEntity.RegisterKey.Split('-');
string[] fakeKeyArgs = new string[4];
if (!Utility.isNullOrEmptyLst(registerEntity.RegisterOrder) && !Utility.isNullOrEmpty(realKeyArgs))
{
for (int i = 0; i < realKeyArgs.Length; i++)
{
fakeKeyArgs[i] = realKeyArgs[registerEntity.RegisterOrder[i]];
}
}
StringBuilder decipherKey = new StringBuilder();
string keyPart = string.Empty;
for (int i = 0; i < fakeKeyArgs.Length; i++)
{
keyPart = fakeKeyArgs[i].ToString() + "-";
decipherKey.Append(keyPart);
}
decipherKey.Remove(decipherKey.Length - 1, 1);
return decipherKey.ToString();
}
细心的朋友会发现,解密其实和加密差不多,只是fakeKeyArgs和realKeyArgs的顺序换下,是的,验证Key的时候是比较fakeKey而不是真正存储在文件里的realKey
6.验证Key的有效性以及是否过期
public bool CheckRegister(string registerFileName)
{
RegisterEntity registerEntity = new RegisterEntity();
try
{
string dBFilePath = string.Format("{0}\\{1}", Directory.GetCurrentDirectory(), registerFileName);
if (File.Exists(dBFilePath))
{
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream(registerFileName, FileMode.Open,
FileAccess.Read, FileShare.Read);
registerEntity = (RegisterEntity)formatter.Deserialize(stream);
stream.Close();
if (registerEntity.IsRegistered == true && registerEntity.ExpireDate < DateTime.Today)
{
registerEntity.IsRegistered = false;
formatter = new BinaryFormatter();
stream = new FileStream(registerFileName, FileMode.Create,
FileAccess.Write, FileShare.None);
formatter.Serialize(stream, registerEntity);
stream.Close();
}
}
}
catch (Exception ex)
{
return false;
}
return registerEntity.IsRegistered;
}
是指打开软件的时候识别序列号是否已经过期或者是否已经注册
7.注册并验证
public bool RegisterKey(string inputKey, string registerFileName)
{
RegisterEntity registerEntity = new RegisterEntity();
try
{
string dBFilePath = string.Format("{0}\\{1}", Directory.GetCurrentDirectory(), registerFileName);
if (File.Exists(dBFilePath))
{
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream(registerFileName, FileMode.Open,
FileAccess.Read, FileShare.Read);
registerEntity = (RegisterEntity)formatter.Deserialize(stream);
stream.Close();
string fakeKey = DecipherRegisterKey(registerEntity);
if (inputKey == fakeKey)
{
registerEntity.IsRegistered = true;
registerEntity.RegisterDate = DateTime.Today;
registerEntity.ExpireDate = registerEntity.RegisterDate.AddDays(30);
//Enable Register Key
formatter = new BinaryFormatter();
stream = new FileStream(registerFileName, FileMode.Create,
FileAccess.Write, FileShare.None);
formatter.Serialize(stream, registerEntity);
stream.Close();
}
}
}
catch (Exception ex)
{
return false;
}
return registerEntity.IsRegistered;
}
输入序列号后,注册,验证序列号是否有效,如果有效,则激活软件