前言:这其实只是一个小功能,只是加解密过程还有点意思,故记录于此。
我们的软件在部署给客户时,通常是私有化部署,只能运行在客户的内网上。在私有化部署之后的软件系统保护上,一直也没有考虑太多,其实如果客户把系统打包复制到其他服务器上也是可以使用的,我们现在已有的客户应该不至于这样。不过,这种风险是存在的,我们应该在技术上加以限制。
基于此需求,我们需要实现一个类似软件注册码校验方案,加解密算法选择RSA。
基本思想
思路上,客户和我们各自持有一套密钥,一套密码包含公钥和私钥,客户持有的我们简称客户私钥和客户公钥,我们持有的简称服务私钥和服务公钥。按照RSA算法,公钥是用来加密信息,而私钥是用来解密信息的,这样如果我有一套公钥和私钥,然后把公钥发给你,那么你就可以使用我的公钥进行加密,然后你把加密后的信息发出来,这时只有我使用我的私钥才能进行解密。这就是RSA算法的基本思想。
算法验证流程
在我们的场景中,客户将自己持有的客户公钥发给我们,而我们也把自己持有的服务公钥发给客户,这样流程大概如下:
简单说就是,用对方的公钥进行加密然后发出去,而对收到的信息则用自己的私钥进行解密。
理清楚这个流程,其实实现并不难。当然这个要做好,在客户端的程序必须要能采集到可靠的硬件指纹信息,这样这个客户端就算是跟这台机进行绑定了,如果伪造信息,则客户端在校验的时候必定通不过的。
代码实现
下面只给出客户端的加解密实现,基于python,其实挺简单的:
import rsa
from .utils import get_sys_key
class ClientSecure:
"""客户端需要做的就是加密本地信息,解密服务端信息"""
# 系统ID
sys_id = ''
# 客户端秘钥文件
client_privkey_f = ''
# 服务端加解密公钥
server_pubkey_f = ''
def __init__(self, sys_id, client_privkey_path, server_pubkey_path):
self.client_privkey_f = client_privkey_path
self.server_pubkey_f = server_pubkey_path
def decode(self, server_reg_msg):
"""使用客户端私钥解密服务器的信息
每次本地服务启动时,都进行一次判断
:param server_reg_msg 文件内容, open(finename, 'rb').read()
"""
with open(self.client_privkey_f, 'rb') as r:
p = r.read()
client_privkey = rsa.PrivateKey.load_pkcs1(p)
server_msg = rsa.decrypt(server_reg_msg, client_privkey)
return str(server_msg, encoding='utf8')
def check(self, server_msg):
"""判断解密之后的服务器端信息是否有效"""
# TODO 可以在这里进行有效期校验
# TODO 测试信息是否正确
sys_msg = get_sys_key(self.sys_id)
if server_msg != sys_msg:
return False
return True
def encode(self):
"""使用服务端公钥加密本地信息
如果是离线模型,通常只需要在第一次启动前生成
"""
with open(self.server_pubkey_f, 'rb') as r:
p = r.read()
server_pubkey = rsa.PublicKey.load_pkcs1(p)
# print('加密')
msg = get_sys_key(self.sys_id)
msg = bytes(msg, encoding="utf8")
crypto = rsa.encrypt(msg, server_pubkey)
return crypto
其中的get_sys_key就是用来获取硬件编码信息的函数。只要客户端和服务器端约定好,还可以进行有效期的校验等。
服务器端的实现其实也是类似。