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

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

RSA加密

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

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

硬件绑定

由于是离线验证,所以我们能很容易想到可以根据电脑的硬件信息生成一串加密字符串,程序根据加密字符串解密出硬件信息,如果解密出来的信息与实际电脑配置信息相同,则认为验证通过。同时我们还可以在字符串上添加一些额外信息,例如有效期,这样就能做到限定时间的功能。

这里以BIOS为例,使用ManagementClass和ManagementObjectCollection读取硬件信息,注意这两个类的命名空间为System.Management

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

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来执行,如果发生异常,则一律认为验证失败。以下是程序界面

 文件读写

验证模块已经完成,但是每次打开都要用户手动输入许可证,及其繁琐,因此我们需要将许可证保存在本地。

首先在D盘创建ducuments目录,在document里创建LICENSE文件,注意需引入命名空间System.IO

首先定义地址

private static string dirname = @"D:\documents";
private static string filename = "LICENSE.dx";
private static string path = System.IO.Path.Combine(dirname, filename);

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

System.IO.Directory.CreateDirectory(dirname);
if (!File.Exists(path))
{
    FileStream fileStream = System.IO.File.Create(path);
    fileStream.Dispose();
}

读取和写入

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将许可证以文本形式写入文件里,而读取也是文本形式读取,所以文件的后缀名可以随便取。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dear_Xuan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值