RSA算法和软件注册
Kingron, 2006
共享软件有一个很重要的部分就是注册码算法,如果注册算法简单,可逆,那么就很容易被破解,生成注册机!因此大家都采用公钥算法来进行注册,例如RSA和ECC(椭圆曲线算法),ECC对抗注册机是非常好的,附件中是FGINT实现的RSA算法,有可以用用,但强度没有ECC好。由于网络上C/C++的算法和库很多,但Delphi/Pascal的非常少,因此就在这里讨论一下RSA在注册码中的应用。
RSA算法具体内容请自己查阅相关资料,这里不做讨论。
下面给出附件单元的使用方法:
首先你需要作一个注册机,自己用。但在注册前,你需要查找一些大素数,并求出公钥和私钥。
利用下面的函数,你可以生成公钥和私钥的Delphi定义:
{
uses FGIntRSA, FGInt;
用法: RSAGetDefines('42789535304218630318941267842', 'qwaayafgehuio79361hfh;$%@!FKSJr22L:A^*OHFAHJL:A', '65537');
它将返回 e, d, n的一些定义。请记录下它的定义。
}
function RSAGetDefines(const Key1, Key2, Key3: string): string;
const
CSSign : array[TSign] of string = ('negative', 'positive');
var
one, two, gcd, d, n, p, q, phi, e, nilGint: TFGInt;
i : Integer;
begin
Base10StringToFGInt(Key1 , p);
PrimeSearch(p);
Base256StringToFGInt(Key2, q);
PrimeSearch(q);
FGIntMul(p, q, n);
p.Number[1] := p.Number[1] - 1;
q.Number[1] := q.Number[1] - 1;
FGIntMul(p, q, phi); // Compute phi(n)
Base10StringToFGInt(Key3, e); // just an odd starting point
Base10StringToFGInt('1', one);
Base10StringToFGInt('2', two);
FGIntGCD(phi, e, gcd);
While FGIntCompareAbs(gcd, one) <> Eq Do
Begin
FGIntadd(e, two, nilGint);
FGIntCopy(nilGint, e);
FGIntGCD(phi, e, gcd);
End;
FGIntModInv(e, phi, d);
FGIntDestroy(nilgint);
Result := Format('e.Sign := %s;'#13#10'SetLength(e.Number, %d);'#13#10,
[CSSign[e.Sign], Length(e.Number)]);
for i := Low(e.Number) to High(e.Number) do
Result := Result + Format('e.Number[%d] := $%x;'#13#10, [i, e.Number[i]]);
Result := Result + #13#10 + Format('d.Sign := %s;'#13#10'SetLength(d.Number, %d);'#13#10,
[CSSign[d.Sign], Length(d.Number)]);
for i := Low(d.Number) to High(d.Number) do
Result := Result + Format('d.Number[%d] := $%x;'#13#10, [i, d.Number[i]]);
Result := Result + #13#10 + Format('n.Sign := %s;'#13#10'SetLength(n.Number, %d);'#13#10,
[CSSign[n.Sign], Length(n.Number)]);
for i := Low(n.Number) to High(n.Number) do
Result := Result + Format('n.Number[%d] := $%x;'#13#10, [i, n.Number[i]]);
end;
有了定义之后,就可以使用RSA算法进行签名和验证了,下面是签名算法,你可以用在自己的注册机中,例如可以使用用户明作为Name输入,生成一个字符串返回给用户作为注册码SerialKey:
function RSASignatureName(const Name: string): string;
var
KeyData : string;
d, n, nilGint: TFGInt;
begin
if Name = '' then Exit;
/// 清在这里把前面记录下的 d 的定义代码粘贴到这里
/// 请在这里把前面记录下的 n 的定义代码粘贴到这里
nilGint.Number := nil;
RSASign(Name, d, n, nilGint, nilGint, nilGint, nilGint, KeyData);
/// EncodeSerialKey 为一个把RSA签名数据转换成可读的ASCII的函数,你可以用Base64编码器代替
Result := EncodeSerialKey(KeyData);
FGIntDestroy(d);
FGIntDestroy(n);
end;
注册机作完了,那么你的共享软件中当然需要验证一下用户的注册码对不对,用下面的函数在你的软件中进行验证即可,如果匹配,返回True,否则返回False,其中Name就是用户给你来注册的用户名,Code就是程序中接收到的用户输入的序列号:
function RSAVerityName(const Name, Code: string): Boolean;
var
desData: string;
e, n: TFGInt;
begin
Result := False;
if Code = '' then Exit;
/// 请在这里把前面记录下的 e 的定义代码粘贴到这里
/// 请在这里把前面记录下的 n 的定义代码粘贴到这里
/// DecodeSerialKey为把可读ASCII数据转换成二进制的函数,你可以用Base64的解码器代替
desData := DecodeSerialKey(Code);
RSAVerify(Name, desData, e, n, Result);
end;