假设有这样一个场景,你接了个私活,帮别人做了一个软件,这个软件没有联网功能。东西做好了,客户还没给钱,说想先试试看。您选择信任客户并将软件发送给他。然后他屏蔽了你。为了避免这种情况的发生,大家首先想到的就是把过期时间写到代码中,时间一到App就会自动销毁。对方付款后,您可以延长或取消硬编码时间。然后重新编译发送给客户。但问题是每次都要重新编译代码发给用户,非常麻烦。有更容易的方法吗?软件能不能一直是软件,只是给用户一个注册码,上面标明有效时间。过期后,您只需要给用户一个新的注册码就可以继续使用了。看到这里,肯定有同学会想,怎么在注册码中指定有效期呢?首先,这个时候一定不能是纯文本的,不然用户自己改,能不能自己扩展。但是如果是加密的话,解密算法必须要放到软件里面。一旦用户对程序进行初始反编译,就可以获得解密算法或对称加密的密钥。因此,我们只能采用非对称加密。在非对称加密中,公钥用于加密,私钥用于解密。如果我们想让软件从注册码中解码出有效时间,是不是应该把私钥放在软件里面呢?私钥是不能泄露的,所以只能把公钥放在软件里。但是能不能用私钥加密,用公钥解密呢?其实这样做是可以的,只不过这不叫私钥加密公钥解密。这称为私钥签名(sign)和公钥验证(verify)。而且,使用这种方式还有一个好处,就是有效时间可以直接明文存储,不用担心用户修改。因为一旦修改,签名将不匹配。假设我们有一个字符串消息,使用私钥,我们可以对这个字符串进行签名,得到一个签名字符串signature。而我们使用公钥来验证消息是否可以生成签名字符串signature。如果消息被修改,或者签名被修改,或者同时修改消息和签名,公钥验证将失败。每种语言都有非对称加密相关的第三方库。我们使用Python中的PyCryptodome进行演示。首先我们在macOS下生成一对公钥和私钥:ssh-keygen-trsa根据提示输入密钥的存放路径即可,如下图:在当前文件夹中,私钥标志和公钥sign.pub。接下来,使用pip安装PyCryptodome:pipinstallpycryptodome接下来,导入公钥和私钥:>>>fromCrypto.PublicKeyimportRSA>>>withopen('sign')asf:...private=f.read()...>>>withopen('sign.pub')asf:...public=f.read()...>>>private_key=RSA.import_key(private)>>>public_key=RSA.import_key(public)由于我们之前使用的是SHA256算法生成密钥,所以需要对需要签名的数据使用SHA256算法生成摘要。这一步在签名和验证签名的时候都需要完成。>>>fromCrypto.HashimportSHA256>>>digest=SHA256.new()>>>message='expire:2022-03-01'>>>digest.update(message.encode())接下来,这个数据已签名:>>>importbase64>>>fromCrypto.SignatureimportPKCS1_v1_5>>>signer=PKCS1_v1_5.new(private_key)>>>code=signer.sign(digest)>>>signature=base64.b64encode(code)>>>print(signature.decode())如下图所示:现在,你只需要把字符串expire:2022-03-01和签名字符串xbelbTNpq8M...一个很长的字符串...只需将其发送给客户即可。客户在软件中输入过期时间字符串和签名字符串后,软件使用公钥验证该字符串是否被其对应的私钥签名:>>>message='expire:2022-03-01'>>>signature='xbelbTNpq8MCFkSxGBoTq7SwQ+oqHRAObrj5p8K2gyY+7uWs5dXGjsQ+GP2XTS5YskCtGjYIBZmAmeM5ey69lRQyk5S1m7t68pYNbUvf3o39Ym0rcmK7XGkBh3euZzVeRErs4JCl7ffTbfcqM4aAsWldDKESrZvaDNQ5DkC8VRYHPBfZfScHqPw/zcHCMRhC9Dch8j9eQlnk8/UKY0MM92jXT4map94PzZRfMLkD4vsciZTtMJm4a42UiiWDUpA6zIgQCYru2YyKspS1uZFE51atYP5DcgPWvJUVRDJS/ZjdPfi9chRjx0dS/Df1sFEreZ7myzXAJP7Y8FA6rvi7EZLlHZ1ViM9tTJp9ut/ZlKgnPAuDCp1JSyKMUk/doVqzUjTqTNHuORe+p3Hhb+xkCASyD8eUH+CyEDVLRcDkSMH5U3o/uONnOQao2o9dbkGiSYNkToElQJ2v20S3MnncPciij8H7iI2dDp1dwt8bkcZOD+E1Tf88LMvRaxB7YnhJ'>>>digest=SHA256.new()>>>digest.update(message.encode())>>>reader=PKCS1_v1_5.new(public_key)>>>reader.verify(digest,base64.b64decode(signature.encode()))True但是如果你篡改消息的内容,然后验证会失败,如下图:软件第一次校验后,可以将过期时间的字符串和签名字符串以文件的形式保存到硬盘,进行校验每次启动软件。再次。被发现是合法的并且没有过期。如果发现过期或者不合法,会再次弹出输入注册码的对话框。
