上传日期:2023-08-24 浏览次数:
所有的一切还得从下面这段对话说起,一看就是自己给自己挖了一个坑@-@。前几天朋友找我要一个公私密钥加解密文件工具,本想让他直接在网上找一个的,但好像并不像我想象的一样,结果他让我帮忙写一个,无奈接下了这个活。后来想了一下这不就是一个比特币勒索病毒吗?感觉还有一点意思,于是想着帮他写一个,自己也可以简单了解一下比特币勒索病毒的工作原理,于是有了这篇文章。
其实这个病毒的工作原理很简单,就是当你触发病毒的时候,它开始注入系统(以便重启还能持续加密),另外开始生成公私密钥(当然也可以不用生成,病毒自带公钥直接加密文件),再通过开启多线程,持续疯狂的加密指定类型的文件即可。很多中毒的网络管理员可能会想着怎么破解加密以后的文件,其实方法很简单,只需要病毒制造者将私钥发给你,并且告诉你加密算法,即可解密成功。否则你永远不可能破解成功,当然如果你有天河计算机使用权,也是有可能解密成功的。为什么这么说呢?因为病毒会对文件进行不对称加密。只要他的密钥长度足够长,那么基本上就没有破解的可能了。下面通过一个简图,我们大概了解一下比特币勒索病毒的基本工作原理。
在开始制作病毒程序之前,我们先来简单介绍一下RSA非对称加密算法。RSA非对称加密算法是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的,而RSA就是他们三人姓氏开头字母拼在一起组成的。RSA是目前最有影响力的非对称加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击,RSA算法基于一个十分简单的数论事实:将两个大质数相乘十分容易,但是想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。下图就是三位大神的合照了。
当然,我们这不是来说它的细节原理,大神的世界木子也说不清楚@-@。下面开始制作病毒…
要想制毒成功,我们需要先利其器,以下是我们需要用到的软件包。
PyCrypto
PyCrypto是Python中密码学方面比较有名的第三方软件包。可惜的是它于2012年停止开发更新。幸运的是有一个该项目的分支PyCrytodome取代了PyCrypto,可以支持Python3.8.2。
pip install pycryptodome
PyQT5
在2012年的时候当时木子还是用的python2.7,所以使用的GUI开发工具是wxpython,但wxpython已经很久不更新,所以为了更好的支持Python3.8的GUI开发,这里选择使用Qt Creator。为什么使用Qt Creator了?其实是因为它和wxPython、VF、VB、Deplin等C/S架构开发软件差不多,容易上手。
# MacOS安装pyqt5,会一并安装pyqt5-dev-tools工具pip install pyqt5#Deepin Linux使用pip无法安装成功,采用apt安装sudo apt install python3-pyqt5#Deepin Linux命令pyuic5需要开发工具包sudo apt install pyqt5-dev-tools#Mac命令行安装,当然也可以通过下载dmg包安装brew cask install qt-creator#Deepin Linux v15.11安装wget http://download.qt.io/archive/qt/5.14/5.14.2/qt-opensource-linux-x64-5.14.2.runchmod +x qt-opensource-linux-x64-5.14.2.run./qt-opensource-linux-x64-5.14.2.run#Deepin Linux v20 Beta安装sudo apt-get install qtcreator#通用安装QtGuipip install QtGui
界面设计
程序界面的设计比较简单,直接通过拖拽控件就可以完成,有兴趣的同学可以去网上找一个对应教程,相对来说还是比较容易上手的。
界面设计完成以后保存对应文件,会生成一个.ui后缀的文件,然后我们需要将对应ui转换成py即可。
#ui文件转py文件pyuic5 -o file_en_decryption_ui1.py file_en_decryption.ui#转换后的python文件# -*- coding: utf-8 -*-from PyQt5 import QtCore, QtGui, QtWidgetsclass Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") # 固定窗口大小 MainWindow.resize(800, 460) MainWindow.setFixedSize(800, 460) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( MainWindow.sizePolicy().hasHeightForWidth()) MainWindow.setSizePolicy(sizePolicy) self.line = QtWidgets.QFrame(MainWindow) self.line.setGeometry(QtCore.QRect(10, 385, 781, 10)) self.line.setFrameShape(QtWidgets.QFrame.HLine) self.line.setFrameShadow(QtWidgets.QFrame.Sunken) self.line.setObjectName("line") self.filepath = QtWidgets.QTextEdit(MainWindow) self.filepath.setGeometry(QtCore.QRect(110, 410, 461, 31)) self.filepath.setObjectName("filepath") self.private_key = QtWidgets.QTextBrowser(MainWindow) self.private_key.setGeometry(QtCore.QRect(410, 40, 380, 306)) self.private_key.setObjectName("private_key") self.decryption = QtWidgets.QRadioButton(MainWindow) self.decryption.setGeometry(QtCore.QRect(580, 415, 52, 20)) self.decryption.setChecked(True) self.decryption.setObjectName("decryption") self.publickey = QtWidgets.QLabel(MainWindow) self.publickey.setGeometry(QtCore.QRect(10, 12, 27, 16)) self.publickey.setObjectName("publickey") self.privatekey = QtWidgets.QLabel(MainWindow) self.privatekey.setGeometry(QtCore.QRect(410, 10, 27, 20)) self.privatekey.setObjectName("privatekey") self.public_key = QtWidgets.QTextBrowser(MainWindow) self.public_key.setGeometry(QtCore.QRect(10, 40, 380, 306)) self.public_key.setObjectName("public_key") self.encryption = QtWidgets.QRadioButton(MainWindow) self.encryption.setGeometry(QtCore.QRect(640, 415, 52, 20)) self.encryption.setObjectName("encryption") self.en_decryption = QtWidgets.QLabel(MainWindow) self.en_decryption.setGeometry(QtCore.QRect(10, 417, 89, 16)) self.en_decryption.setObjectName("en_decryption") self.apply = QtWidgets.QPushButton(MainWindow) self.apply.setGeometry(QtCore.QRect(700, 409, 87, 32)) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.apply.sizePolicy().hasHeightForWidth()) self.apply.setSizePolicy(sizePolicy) self.apply.setObjectName("apply") self.generate = QtWidgets.QPushButton(MainWindow) self.generate.setGeometry(QtCore.QRect(700, 350, 87, 32)) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.generate.sizePolicy().hasHeightForWidth()) self.generate.setSizePolicy(sizePolicy) self.generate.setObjectName("generate") self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "文件加解密工具")) self.decryption.setText(_translate("MainWindow", "解密")) self.publickey.setText(_translate("MainWindow", "公钥")) self.privatekey.setText(_translate("MainWindow", "私钥")) self.encryption.setText(_translate("MainWindow", "加密")) self.en_decryption.setText(_translate("MainWindow", "加密&解密文件")) self.apply.setText(_translate("MainWindow", "应用(A)")) self.generate.setText(_translate("MainWindow", "生成(G)"))
公钥和私钥
对应代码块重点区域木子都已经注释了,这里就不详细说了。
from PyQt5.QtWidgets import QApplication, QMainWindowfrom file_en_decryption_ui import *from Crypto.PublicKey import RSAfrom PyQt5 import QtGuiimport en_decryptimport platformimport sysclass MyWindow(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(MyWindow, self).__init__(parent) self.setupUi(self) # 生成密钥 self.generate.clicked.connect(self.createkey) self.apply.clicked.connect(self.en_decryptionfile) def createkey(self): code = "muzilee_www.oubayun.com" # 生成 2048 位的 RSA 密钥 key = RSA.generate(2048) encrypted_key = key.exportKey(passphrase=code, pkcs=8, protection="scryptAndAES128-CBC") # 生成私钥 self.private_key.setText(str(encrypted_key, encoding="utf-8")) with open("rsa_private.key", "wb") as f: f.write(encrypted_key) # 生成公钥 self.public_key.setText( str(key.publickey().exportKey(), encoding="utf-8")) with open("rsa_public.key", "wb") as f: f.write(key.publickey().exportKey()) def en_decryptionfile(self): systemtype = platform.system() if systemtype == "Windows": filepathvalue = self.filepath.toPlainText().replace("file:///", "") else: filepathvalue = self.filepath.toPlainText().replace("file://", "") if filepathvalue: # 解密按钮值(True&False) decryptionvalue = self.decryption.isChecked() if str(decryptionvalue) == "True": destatus = en_decrypt.Descrypt(filepathvalue) self.public_key.setText(destatus) else: enstatus = en_decrypt.Encrypt(filepathvalue) self.private_key.setText(enstatus)if __name__ == '__main__': #GUI界面显示 app = QApplication(sys.argv) myWin = MyWindow() myWin.setWindowIcon(QtGui.QIcon("logo.ico")) myWin.show() sys.exit(app.exec_())
加解密
from Crypto.Cipher import AES, PKCS1_OAEPfrom Crypto.Random import get_random_bytesfrom Crypto.PublicKey import RSAdef Encrypt(filename): data = '' # 二进制只读打开文件,读取文件数据 with open(filename, 'rb') as f: data = f.read() with open(filename, 'wb') as out_file: # 收件人秘钥 - 公钥 recipient_key = RSA.import_key( open('rsa_public.key').read()) #一个 16 字节的会话密钥 session_key = get_random_bytes(16) # Encrypt the session key with the public RSA key cipher_rsa = PKCS1_OAEP.new(recipient_key) out_file.write(cipher_rsa.encrypt(session_key)) # Encrypt the data with the AES session key cipher_aes = AES.new(session_key, AES.MODE_EAX) ciphertext, tag = cipher_aes.encrypt_and_digest(data) out_file.write(cipher_aes.nonce) out_file.write(tag) out_file.write(ciphertext) return ("文件: %s 加密成功" % filename)def Descrypt(filename): code = 'muzilee_www.oubayun.com' with open(filename, 'rb') as fobj: # 导入私钥 private_key = RSA.import_key( open('rsa_private.key').read(), passphrase=code) # 会话密钥, 随机数,消息认证码,机密的数据 enc_session_key, nonce, tag, ciphertext = [ fobj.read(x) for x in (private_key.size_in_bytes(), 16, 16, -1) ] cipher_rsa = PKCS1_OAEP.new(private_key) session_key = cipher_rsa.decrypt(enc_session_key) cipher_aes = AES.new(session_key, AES.MODE_EAX, nonce) # 解密 data = cipher_aes.decrypt_and_verify(ciphertext, tag) with open(filename, 'wb') as wobj: wobj.write(data) return ("文件: %s 解密成功" % filename)
通过上面的代码块,基本已经实现了功能所需,下面我们来演示一下。
生成公钥和私钥,这时候我们就可以看到对应的公钥和私钥了,为了方便朋友使用,所以在对应程序根目录,木子保存了一份公钥和私钥的key(rsa_private.key,rsa_public.key)。
当然每次生成的公钥和私钥都是不一样的,公钥给任何人都没有关系,但是私钥一定要保存好,否则一旦泄露,意味着你的加密文件就不安全了。
这里我们测试加密hello.txt文件,如下图所示,加密成功。
再打开hello.txt就是密文了。
我们再进行解密,就可以看到对应原文了。
它仅仅只能加密txt文档吗?错了,它可以加密所有文件类型的。这里我们再来加密一个图片文件。
加密后再打开会现提示文件已经损坏。
至此,一个简单的文件加解密工具就制作完成。
以上加解密工具仅供学习参考,请勿滥用,一切后果自负。当然我们这里看到的只是一个简单的文件加密工具,说好的比特币勒索病毒了?其它我们只需要将其GUI移除,然后加上多线程并发…..,编不下去了@-@,这篇文章就简单写到这里了。欢迎各位点赞、转发、加评论。