该方案主要是针对盗版问题的。
基本步骤
1、在发布给用户的软件中插入有授权验证代码,用户首次使用软件时,软件先获取计算机硬件信息,并将其编码生成一串申请码,随用户输入的用户名和密码发送往服务器进行验证。
2、服务器首先验证用户名密码是否合法,若合法则使用私钥对申请码签名,生成一串授权码,并随配对的公钥发送给用户软件。
3、软件收到授权码和公钥后存到本地并运行验证程序,使用公钥验证签名,解密获得明文。再次获取计算机硬件信息并生成申请码,将其与明文对比,若对比一致则合法,可以继续使用软件。
4、二次使用软件时,无需联网,直接读取本地的授权码和公钥,运行验证程序。
编码算法
指将计算机硬件信息编码生成申请码的算法。其实就是使用Hash算法,一般可以使用SHA1,严格一点可以使用SHA256或更高安全等级的算法。
签名算法
指将申请码签名和验证的算法。这里采用的是 ECDSA (椭圆曲线数字签名算法),因为其安全等级较 RSA 等算法更高。
面临的问题
1、获取哪些硬件信息?
很多人会更换计算机的某些硬件,比如硬盘。所以应该尽量避免去获取可能变动的硬件信息。因此选择去获取主板序列号和CPU序列号是一个不错的选择(不用担心用户更换主板和CPU,这种情况是极少的,做特殊情况处理即可,比如开通申诉渠道)。
2、传输申请码和授权码的安全问题。
传输通道的安全是必须要保证的,否则也会遭到伪造授权服务器的威胁。可以考虑 SSH 等算法,再结合其他的技术验证手段来增强通道的安全性。
3、公钥的发布方式。
【简述】中的第3步提到的公钥下发模式是基于每次授权请求都重新生成一对公私钥的思路。实际应用时可以按软件的批次,每一批次生成、使用一对公私钥,并把公钥内置在软件中。
4、软件迭代是不是要重新验证呢?
这个根据软件发行商的策略调整。如果每次迭代都需要重新授权,那么申请码就可以加入软件的版本信息,每次迭代都重新使用一对公私钥进行验证。如果不需要,那就不要变更公私钥,申请码也保持前后一致。
5、其他。
待补充,欢迎提出问题或建议!
应该注意
1、生成私钥时的 K 值。
生成私钥时需要依据一个 K 值进行计算,这个 K 值应该是随机生成的,每次都要不一样,否则很容易遭到破解。索尼 PlayStation 3 游戏机就犯了这样的错误:他们把 K 值写成了静态的。
2、高精度整数运算
计算机的存储是有长度限制的,比如 32 位计算机能够存储的最大符号型整数常量是 2 147 483 647 (2^31-1),如果输入 2 147 483 648,类型就变成了浮点型,后续的计算就会越来越不精确,以至于得到的并不是我们想要的结果。
这个时候就需要进行高精度整数运算,先把整形数值存为字符串,再进行计算。C#提供了 BigInteger 类(.net 4.0 以上),PHP则内置了 GCD 库。你也可以自己编译 GCD 库使用。
3、MOD 运算问题。
9 除以 4 ,余数是多少?毫无疑问是 1 。
那么,-9 除以 4,余数是多少?是 -1 还是 3 ?
负数取余是一个存在争议的数学问题,我们不去辩论,统一采用正余数。C# 中这样计算:
public static BigInteger MathMod(BigInteger a, BigInteger b)
{
return (BigInteger.Abs(a * b) + a) % b; //BigInteger.Abs() 是求绝对值
}
4、GCD 运算
即计算最大公约数。有两种算法可供选择:欧几里德算法(辗转相除法)和《九章算术》中提出的更相减损法。
欧几里德算法的伪代码:
int gcd(int a, int b){
int t = 0;
while(b != 0){
t = b;
b = mod(a, b);
a = t;
}
return a;
}
5、其他
(待续)