前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >利用RSA加密实现的简易离线验证功能(C#,含代码)

利用RSA加密实现的简易离线验证功能(C#,含代码)

作者头像
DearXuan
发布2022-01-19 18:01:42
4380
发布2022-01-19 18:01:42
举报

许多软件都有正版验证功能,它们通常需要联网验证,验证的本质则是加密与解密,本文将使用RSA加密算法实现简易的离线验证功能

RSA加密

设p,q是两个超级大的素数,N=pq,数据通过欧拉函数φ(N)来加密,而欧拉函数φ(N)满足φ(N)= φ(pq)=(p-1)(q-1),如果要算出φ(N),就必须知道p和q。并且这有一点好处,某人可以公开宣布他的密钥e以及N,任何人都可以给他发送密文,但是只有他能看懂。因为想要破解密码,就必须知道那两个超级大素数p,q.

DearXuan
DearXuan

p和q的位数决定了密文的安全性。

硬件绑定

由于是离线验证,所以我们能很容易想到可以根据电脑的硬件信息生成一串加密字符串,程序根据加密字符串解密出硬件信息,如果解密出来的信息与实际电脑配置信息相同,则认为验证通过。同时我们还可以在字符串上添加一些额外信息,例如有效期,这样就能做到限定时间的功能。 这里以BIOS为例,使用ManagementClass和ManagementObjectCollection读取硬件信息,注意这两个类的命名空间为System.Management

代码语言:javascript
复制
ManagementClass mc = null;
ManagementObjectCollection moc = null;
try
{
    mc = new ManagementClass("Win32_BIOS");
    moc = mc.GetInstances();
    foreach (ManagementObject mo in moc)
    {
        bios = mo.Properties["SerialNumber"].Value.ToString();
        break;
    }
}
catch(Exception ex)
{
    bios = null;
}
finally
{
    if (mc != null) mc.Dispose();
    if (moc != null) moc.Dispose();
}

程序读取了BIOS编号,并保存在bios字符串中 现在根据BIOS编号生成密文,C#提供了RSACryptoServiceProvider来帮助加密,注意这个类的命名空间为System.Security.Cryptography

代码语言:javascript
复制
public static string Encrypt(string content)
{
    string publickey = @"<RSAKeyValue><Modulus>5m9m14XH3oqLJ8bNGw9e4rGpXpcktv9MSkHSVFVMjHbfv+SJ5v0ubqQxa5YjLN4vc49z7SVju8s0X4gZ6AzZTn06jzWOgyPRV54Q4I0DCYadWW4Ze3e+BOtwgVU1Og3qHKn8vygoj40J6U85Z/PTJu3hN1m75Zr195ju7g9v4Hk=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
    RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
    byte[] cipherbytes;
    rsa.FromXmlString(publickey);
    cipherbytes = rsa.Encrypt(Encoding.UTF8.GetBytes(content), false);
    return Convert.ToBase64String(cipherbytes);
}
 
public static string Decrypt(string content)
{
    string privatekey = @"<RSAKeyValue><Modulus>5m9m14XH3oqLJ8bNGw9e4rGpXpcktv9MSkHSVFVMjHbfv+SJ5v0ubqQxa5YjLN4vc49z7SVju8s0X4gZ6AzZTn06jzWOgyPRV54Q4I0DCYadWW4Ze3e+BOtwgVU1Og3qHKn8vygoj40J6U85Z/PTJu3hN1m75Zr195ju7g9v4Hk=</Modulus><Exponent>AQAB</Exponent><P>/hf2dnK7rNfl3lbqghWcpFdu778hUpIEBixCDL5WiBtpkZdpSw90aERmHJYaW2RGvGRi6zSftLh00KHsPcNUMw==</P><Q>6Cn/jOLrPapDTEp1Fkq+uz++1Do0eeX7HYqi9rY29CqShzCeI7LEYOoSwYuAJ3xA/DuCdQENPSoJ9KFbO4Wsow==</Q><DP>ga1rHIJro8e/yhxjrKYo/nqc5ICQGhrpMNlPkD9n3CjZVPOISkWF7FzUHEzDANeJfkZhcZa21z24aG3rKo5Qnw==</DP><DQ>MNGsCB8rYlMsRZ2ek2pyQwO7h/sZT8y5ilO9wu08Dwnot/7UMiOEQfDWstY3w5XQQHnvC9WFyCfP4h4QBissyw==</DQ><InverseQ>EG02S7SADhH1EVT9DD0Z62Y0uY7gIYvxX/uq+IzKSCwB8M2G7Qv9xgZQaQlLpCaeKbux3Y59hHM+KpamGL19Kg==</InverseQ><D>vmaYHEbPAgOJvaEXQl+t8DQKFT1fudEysTy31LTyXjGu6XiltXXHUuZaa2IPyHgBz0Nd7znwsW/S44iql0Fen1kzKioEL3svANui63O3o5xdDeExVM6zOf1wUUh/oldovPweChyoAdMtUzgvCbJk1sYDJf++Nr0FeNW1RB1XG30=</D></RSAKeyValue>";
    RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
    byte[] cipherbytes;
    rsa.FromXmlString(privatekey);
    cipherbytes = rsa.Decrypt(Convert.FromBase64String(content), false);
    return Encoding.UTF8.GetString(cipherbytes);
}

两部分核心代码已经完成,在程序中先获取BIOS编号,然后提示用户输入许可证,这个许可证实际上就是密文,程序解密密文,这里需要注意的是,如果用户输入的密文格式有误,则解密函数会抛出异常,因此需要套上try来执行,如果发生异常,则一律认为验证失败。以下是程序界面

DearXuan
DearXuan
DearXuan
DearXuan

文件读写

验证模块已经完成,但是每次打开都要用户手动输入许可证,及其繁琐,因此我们需要将许可证保存在本地。 首先在D盘创建ducuments目录,在document里创建LICENSE文件,注意需引入命名空间System.IO 定义地址

代码语言:javascript
复制
private static string dirname = @"D:\documents";
private static string filename = "LICENSE.dx";
private static string path = System.IO.Path.Combine(dirname, filename);

创建目录和文件,这里需注意Create后必须dispose,否则接下来读取时会提示被占用

代码语言:javascript
复制
System.IO.Directory.CreateDirectory(dirname);
if (!File.Exists(path))
{
    FileStream fileStream = System.IO.File.Create(path);
    fileStream.Dispose();
}

读取和写入

代码语言:javascript
复制
public static string ReadFile()
{
    string key = "";
    string line;
    StreamReader sr = null;
    try
    {
        sr = new StreamReader(path);
        while ((line = sr.ReadLine()) != null)
        {
            key += line;
        }
    }
    catch(Exception ex)
    {
        key = null;
    }
    finally
    {
        if(sr != null)
        {
            sr.Dispose();
        }
    }
    return key;
}
 
public static void WriteFile(string key)
{
    StreamWriter sw = null;
    try
    {
        sw = new StreamWriter(path);
        sw.Write(key);
    }
    catch (Exception ex)
    { }
    finally
    {
        if (sw != null)
        {
            sw.Dispose();
        }
    }
}

StreamReader和StreamWriter可以放在using里面执行,这样就会自动销毁,但是为了显示dispose的重要性,本程序中手动dispose StreamReader将许可证以文本形式写入文件里,而读取也是文本形式读取,所以文件的后缀名可以随便取。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021年7月13日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • RSA加密
  • 硬件绑定
  • 文件读写
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档