Python:用RSA加密算法(使用公钥和私钥)对软件进行加密

欢迎关注我的微信公众号:MatlabGUI QtCPP等学习记录

 

前言

昨天老师找我,让我给软件整一个加密的功能,不能让别人随便拷贝都能用。

开始时我搜了一下加密狗,感觉这个也不方便一个软件就要一个加密狗。用加密狗的话,需要你的软件去读取这个加密狗的信息,感觉这个也不好整。

所以还是找一找通过软件来加密的办法。如果要联网验证的话,我还得整一个服务器给老师,然后还要写一个服务端的程序,感觉不划算,还是离线吧。

离线验证,有一个安全的方法是:使用公钥和私钥。实际上就相当于根据客户的计算的硬件特征,单独发送一个许可证给客户。只有我给用户发了这个许可证之后,他才能使用。


公钥和私钥,是RSA加密算法方面的东西,我没找到现成的C++库。我看一些例子是调用openssl这个三方库,但是这个库我下载不下来:)。有的大佬甚至自己写,然而我只是一条机械专业的菜狗,不懂密码学,只想着找轮子。折腾好久,感觉用C++我是整不出来了,然后就想着用Python来做这项工作吧,反正老师让做的这软件也要用到Python,正好发现Python有一个加密算法库:pycryptodome

公钥和私钥可以用于加密和解密:

  • 公钥加密

  • 私钥解密

私钥和公钥还可以用于数字签名及验证:

  • 私钥产生数字签名

  • 公钥用于验证私钥产生的数字签名

对软件进行加密采用的是:私钥和公钥的数字签名及验证

我不懂密码学,理论原理方面我不好表述,万一说错了还误导大家。我在B站上看到一个国外的小姐姐讲的挺好的,大家可以去看看:https://www.bilibili.com/video/BV1AW41197yV?from=search&seid=15899869232401830710

我这篇推送主要是总结整理对软件进行加密的步骤,理论方面目前不是重点(我不会)。

使用公钥私钥来加密软件的主要步骤

1. 在我自己的电脑上:

  • 生成 公钥和私钥 对(生成后就不要再动它了)

  • 把公钥编译到exe程序中

  • 私钥自己偷偷保留好

  • 把exe程序发送给客户

2. 在客户的电脑上运行程序时:

  • 获取硬件信息生成硬件指纹

  • 让客户把硬件指纹发送给我,我通过私钥来生成客户硬件指纹的签名文件

  • 客户把指纹签名文件复制到程序的目录中

  • 客户点击验证后,程序内部会根据公钥来对这个指纹签名进行验证

需要安装的两个库

  • .\pip.exe install pycryptodome

  • .\pip.exe install wmi

我这边要完成的工作

生成 公私钥 对

  • 必须成对生成。

  • 私钥自己保留藏好,后面用于生成数字签名。

  • 公钥则跟软件一块发送给客户,客户端用公钥来验证数字签名。数字签名是在客户发给我指纹后,我利用私钥来对指纹生成数字签名。

  • 最好把公钥放到资源文件里,最后编译到exe中。不然碰到懂行的大哥,他可能直接拿自己的公钥来替换掉你的公钥。要是编译到exe中的话,别人就无法替换公钥了,只能用你的私钥生成的数字签名来验证。

  • 私钥文件最好也编译到生成签名的exe软件中(自己做一个注册机)。

  • 生成公私钥的这个代码运行一次就可以了,主要就是为了生成公私钥文件的。

GenerateKeyFile.py

from Crypto.PublicKey import RSA

key = RSA.generate(2048)


def prepare_key_file():
    r"""生成公钥文件和私钥文件

    """

    private_key = key.export_key()  # 私钥
    public_key = key.publickey().export_key()  # 公钥

    # 把公私钥保存到文件(.pem)
    with open("private_key.pem", "wb") as private_file, \
            open("public_key.pem", "wb") as public_file:
        private_file.write(private_key)
        public_file.write(public_key)


if __name__ == '__main__':
    prepare_key_file()

生成签名文件

根据客户发过来的硬件指纹,来生成签名文件,然后再把签名文件发送给客户。所以这部分工作不是一开始就能做的,需要把软件给客户后,我才可能做这项工作。

GenerateSignature.py

"""
在客户端使用,公钥提前发给客户了;
私钥自己留着,等客户发来摘要后,对摘要进行签名;
把签名发给客户,验证程序根据公钥对签名进行验证
"""


from Crypto.Signature import pkcs1_15
from Crypto.Hash import MD5
from Crypto.PublicKey import RSA


def get_digest(fingerprint):
    """
    获取硬件指纹的摘要
    :param fingerprint: 硬件指纹
    :return: 返回硬件指纹的摘要
    """

    return MD5.new(fingerprint.encode('utf-8'))


def generate_signature(private_key, digest):
    """定义签名函数,能够使用指定的私钥对数据文件进行签名,并将签名结果输出到文件返回

    :param private_key: 私有密钥
    :param digest: 用户发过来的摘要(十六进制值)
    :return: 无,签名结果直接写入文件了
    """

    # 使用私钥对HASH值进行签名
    signature = pkcs1_15.new(private_key).sign(digest)

    # 将签名结果写入文件
    sig_results = open("sig_results.txt", "wb")
    sig_results.write(signature)
    sig_results.close()


if __name__ == "__main__":
    # 导入私有密钥
    with open('private_key.pem') as private_file:
        private_key_ = RSA.import_key(private_file.read())

    # 输入用户发来的指纹特征
    fingerprint_ = "239af1404f79b42e11b5aea5a8aa85ec"

    # 获取指纹摘要
    digest_ = get_digest(fingerprint_)

    # 用自己的私有密钥对摘要进行签名(签名结果在sig_results.txt中)
    generate_signature(private_key_, digest_)

客户程序中要完成的工作

需要这两个py文件,这两个文件里都写成函数的形式,不要写成类,方便以后用C++来调用他们。

获取硬件指纹

我取的硬件信息为:

  • cpuid +

  • systemName +

  • 主板的SerialNumber +

  • 所有硬盘的SerialNumber +

  • 所有memory的SerialNumber

这些字符拼接起来作为计算机的硬件信息,然后对这个硬件信息进行MD5加密获取硬件信息的摘要,即生成硬件指纹。

客户在获取硬件指纹后,需要把硬件指纹复制发给我用来生成签名!

GetHardwareCharacteristic.py

import wmi
from Crypto.Hash import MD5


c = wmi.WMI()


def get_hardware_characteristic():
    """
    获取硬件指纹特征:
        cpuid + systemName + 主板的SerialNumber + 所有硬盘的SerialNumber + 所有memory的SerialNumber

    :return: 返回硬件指纹特征
    """
    # 初始化指纹特征为空字符串
    fingerprint = ""

    # 获取所有cpu的id和systemName
    for cpu in c.Win32_Processor():
        fingerprint = fingerprint + cpu.ProcessorId.strip()
        fingerprint = fingerprint + cpu.SystemName.strip()

    # 获取主板的序列号
    for board_id in c.Win32_BaseBoard():
        fingerprint = fingerprint + board_id.SerialNumber.strip()

    # 获取所有硬盘的的序列号
    for disk in c.Win32_DiskDrive():
        fingerprint = fingerprint + disk.SerialNumber.strip()

    # 获取所有内存的的序列号
    for mem in c.Win32_PhysicalMemory():
        fingerprint = fingerprint + mem.SerialNumber.strip()

    # 返回指纹
    return MD5.new(fingerprint.encode('utf-8')).hexdigest()


# if __name__ == '__main__':
#     print(get_hardware_characteristic())

你可以少取一点硬件信息,或者取某一个硬件的信息。

客户端验证签名

ClientVerification.py

"""
在客户端使用,公钥提前发给客户了;
私钥自己留着,等客户发来指纹后,对指纹摘要进行签名;
把签名发给客户,验证程序根据公钥对签名进行验证
公钥不能放在文件中,要一块编译到exe里面。不然别人拿自己的公钥来替换就完蛋了
"""


from Crypto.Signature import pkcs1_15
from Crypto.Hash import MD5
from Crypto.PublicKey import RSA
import GetHardwareCharacteristic


def get_digest(fingerprint):
    """
    获取硬件指纹的摘要
    :param fingerprint: 硬件指纹
    :return: 返回硬件指纹的摘要
    """

    return MD5.new(fingerprint.encode('utf-8'))


def verifier(public_key, digest, signature):
    """
    利用公钥,验证签名
    :param public_key: 公钥
    :param digest: 硬件指纹的摘要
    :param signature: 签名
    :return:
    """
    try:
        pkcs1_15.new(public_key).verify(digest, signature)
        print("验证通过!!!")
        return True
    except ValueError:
        print("签名无效,请联系作者购买签名文件!!!")
        return False


if __name__ == "__main__":
    # 打开签名文件(在后面生成exe时,需要把公钥编译到exe中,不能放文件里)
    with open('public_key.pem') as public_file, open('sig_results.txt', 'rb') as sig_file:
        public_key_ = RSA.import_key(public_file.read())  # 导入公钥
        signature_ = sig_file.read()  # 读取公钥

    # 获取硬件指纹
    fingerprint_ = GetHardwareCharacteristic.get_hardware_characteristic()
    print(fingerprint_)

    # 指纹摘要(用于验证)
    digest_ = get_digest(fingerprint_)

    # 验证签名
    verifier(public_key_, digest_, signature_)

Note: 在生成exe时,这个公钥必须一块编译到exe程序文件中。不然懂行的大哥就可能就拿他自己的公钥来替换我的公钥了,然后他就能拿他自己的私钥来生成签名。这样就失去了加密软件的目的,所以要把公钥一块编译到exe程序里。

现在这个软件也没做好,所以这里为了测试效果就放在__main__模块中来运行下看看,我也懒得再写个界面了。

我用PPT大概画了一个验证的界面!

测试加密功能

我在我的本地机器上生成签名文件给本地的验证程序试一下;
然后再用这个本地的签名文件拿到Win10虚拟机中试一下;

本地测试,验证通过

执行:GenerateKeyFile.py 生成公钥和私钥:

把公钥拿走,放到验证程序的文件夹中:

执行:GetHardwareCharacteristic.py获取硬件指纹:

把签名文件复制到验证程序中,执行验证程序:


拿相同的签名文件,换一台机器试试

这个是在Win10虚拟机上测试的!

可见,硬件指纹不一样,拿着其他电脑的签名肯定是验证不通过的,如果你想通过更改计算机硬件信息来改变硬件指纹是不现实的,所以你只能联系我购买数字签名了!

参考价值最大的两篇博文

  • 获取计算机硬件信息:https://blog.csdn.net/fengmm521/article/details/79468677

  • pycryptodome库简介:https://blog.csdn.net/weixin_42323041/article/details/105832325

  • 3
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值