基于C#实现简单离线注册码生成与验证
作者:mrr 时间:2022-02-08 15:22:49
主要思路就是提供者持有密钥,通过RSA加密客户机标识或时间标识,再通过Base64加密成不太难看的注册码,然后分发给客户机。
客户机解Base64后,通过持有的公钥来验证注册码是否与本机标识或时间标识相符。
一、 生成公密钥
RSACryptoServiceProvider cryptor = new RSACryptoServiceProvider();
File.WriteAllText("PrivateKey.xml", cryptor.ToXmlString(true));
File.WriteAllText("PublicKey.xml", cryptor.ToXmlString(false));
为了方便长期保存这里就直接存入文件了。
为了避免客户机公钥丢失,我比较倾向于将公钥直接编译到验证程序中,但是这样也就意味着如果更换了密钥,老的验证程序就验不了新生成的注册码了。
二、 生成注册码
static string CreateRegCode(string mac, DateTime date)
{
RSACryptoServiceProvider cryptor = new RSACryptoServiceProvider();
cryptor.FromXmlString(File.ReadAllText("PrivateKey.xml"));
string signature = String.Format("[{}][{}]", mac, date.ToString("yyyy-MM-dd"));
byte[] regCodeBytes = cryptor.SignData(
Encoding.UTF.GetBytes(signature),
"SHA");
return Convert.ToBaseString(regCodeBytes);
}
这个方法是通过加密MAC和日期的组合来生成注册码,需要注意几点:
1.参数中的MAC是客户机的地址2.第四行的文件是上一步生成的密钥文件
3.由于只考虑验证,所以客户机还必须知道参数中的date
三、 验证注册码
static bool Verify(string regCode)
{
const string PUBLIC_KEY = "";
try
{
RSACryptoServiceProvider cryptor = new RSACryptoServiceProvider();
cryptor.FromXmlString(PUBLIC_KEY);
byte[] signedData = Convert.FromBaseString(regCode);
bool today = cryptor.VerifyData(
Encoding.UTF.GetBytes(String.Format("[{}][{}]", DateTime.Now.ToString("yyyy-MM-dd"))),
"SHA", signedData);
bool machineToday = cryptor.VerifyData(
Encoding.UTF.GetBytes(String.Format("[{}][{}]", MAC, DateTime.Now.ToString("yyyy-MM-dd"))),
"SHA", signedData);
bool forever = cryptor.VerifyData(
Encoding.UTF.GetBytes(String.Format("[{}][{}]", MAC, Environment.MachineName)),
"SHA", signedData);
return today || machineToday || forever;
}
catch
{
return false;
}
}
这个方法验证了三种类型的注册码:当天可用、本机当天可用和永久可用。
需要注意:
1.第三行的公钥就是第一步的PublicKey.xml中的内容
2.十四和十七行的MAC是客户机的物理地址,至于怎么获取不是本文的重点,请各位看官自行百度
3.考虑到客户机填写的注册码有可能不是合法的Base64文本,需要捕获解析时异常
其实RSACryptoServiceProvider也提供了解密的方法,这样就可以验证更多种类的验证码了。
标签:离线注册码,生成,验证
![](/images/zang.png)
![](/images/jiucuo.png)
猜你喜欢
JDK1.8中的ConcurrentHashMap源码分析
2023-11-27 06:02:32
![](https://img.aspxhome.com/file/2023/1/60481_0s.jpg)
Spring Boot整合Swagger测试api构建全纪录
2022-10-21 09:05:25
并行Stream与Spring事务相遇会发生什么?
2022-08-28 15:40:12
![](https://img.aspxhome.com/file/2023/4/85944_0s.webp)
Java超详细分析@Autowired原理
2023-11-25 05:37:44
![](https://img.aspxhome.com/file/2023/9/60059_0s.png)
使用@TransactionalEventListener监听事务教程
2023-10-05 02:50:44
java实现分布式项目搭建的方法
2022-10-13 10:42:36
![](https://img.aspxhome.com/file/2023/2/96262_0s.png)
Java命令设计模式优雅解耦命令和执行提高代码可维护性
2023-11-23 06:25:46
![](https://img.aspxhome.com/file/2023/1/59861_0s.png)
Java数据封装树形结构代码实例
2022-04-12 08:11:44
一次由Lombok的@AllArgsConstructor注解引发的错误及解决
2023-10-07 05:23:42
![](https://img.aspxhome.com/file/2023/3/58683_0s.png)
Android使用URL读取网络资源的方法
2023-07-27 10:56:39
![](https://img.aspxhome.com/file/2023/6/63836_0s.png)
Java异常的处理机制
2023-12-03 15:33:19
![](https://img.aspxhome.com/file/2023/7/71147_0s.png)
C#实现WPF项目复制和移动文件夹
2023-06-07 16:49:16
C++ 反汇编之关于Switch语句的优化措施
2023-09-10 15:00:15
![](https://img.aspxhome.com/file/2023/5/99285_0s.png)
SpringBoot多数据源配置详细教程(JdbcTemplate、mybatis)
2023-08-26 01:59:33
深入了解Java核心类库--Math类
2023-08-19 01:06:21
SpringMVC中使用@PathVariable绑定路由中的数组的方法
2023-11-27 14:21:01
![](https://img.aspxhome.com/file/2023/9/61289_0s.png)
Java继承Thread类创建线程类示例
2023-08-04 20:27:08
SpringBoot 项目瘦身maven/gradle详解
2021-10-26 04:39:12
JAVA如何定义构造函数过程解析
2023-11-04 08:15:09
![](https://img.aspxhome.com/file/2023/7/58477_0s.png)
SpringBoot系列教程之防重放与操作幂等
2021-12-07 11:51:12
![](https://img.aspxhome.com/file/2023/3/68703_0s.jpg)