赞
踩
前言:嵌入式单片机开发,为了防止别人将芯片内的代码读取出来通过反编译手段拿到源码,常用的手段是对芯片和烧录文件进行加密。大部分的芯片厂商都会提供一个加密烧录和配置文件的工具。这个工具一般需要你填写一定长度的密钥,如果密钥填写得太有规律比如:123456,或项目名+版本号等,这样的密钥对公司来说极度不安全,如果被对手知道别人很可能直接破解出你的源码,然后抄一下你的板就和你一模一样出货了,别人省去了开发成本何乐不为呢?所以本文介绍一种通过AES加密算法将明文转换为密文的工具制作。AES加密算法目前没有破解办法,据我所知微信小程序就用到了这种加密算法。
制作这样的工具只需要三个模块即可完成,AES加密算法模块、芯片加密模块、GUI模块。本文使用Pathon3语言开发。
AES加密是一种常见的对称加密算法,具有较高的安全性。之所以选择用Python3来做这个工具,就是因为其丰富的现成模块支持,没必要重复造轮子,Windows下我们直接导入pycryptodome模块。由于是对称加密其基本形式是明文+密钥=密文
,密文+密钥=明文
虽然AES算法不用我们实现,但是其原理和参数需要有一定的了解。实现一次AES运算需要输入密钥、明文、模式、偏移量、字符集类型、数据块、填充内容。输出即是密文。
''' @file AESCrypt.py @brief AES加密算法类 @details 创建该对象进行AES加密 @author Calm @data 2020-03-13 @version 1.0.0 @copyright Calm ''' from Crypto.Cipher import AES # Window下需要安装pycryptodome模块 import base64 class AESCrypt: ''' @fn __init__(self, Key, Model, IV, Encode, DataBlockLen, SupplementChar) @brief 带参构造函数,输入AES加密的参数。 @details ECB加密模式无偏移量IV,CBC需要设置IV。需要确保密钥进行了块化。 @param[in] Key 加密密钥。 @param[in] Model 加密模式(ECB、CBC等)。 @param[in] IV 加密偏移量。 @param[in] Encode 字符集类型(gb2312、gbk等)。 @param[in] DataBlockLen 数据块(单位是字节)(密钥和明文长度需是128、192、256Bit的倍数。 @param[in] SupplementChar 对数据块进行填充,使得数据为128、192、或256Bit的倍数。 @return None @note 无。 @attention 无 ''' def __init__(self, Key, Model, IV, Encode, DataBlockLen, SupplementChar): self.AESEncode = Encode self.SupplementChar = SupplementChar self.AESModel = {'ECB': AES.MODE_ECB, 'CBC': AES.MODE_CBC}[Model] self.AESDataBlockLen = DataBlockLen self.AESSupplementKey = self.DataBlock(Key, self.AESDataBlockLen, self.SupplementChar) if Model == 'ECB': self.AES = AES.new(self.AESSupplementKey, self.AESModel) elif Model == 'CBC': self.AES = AES.new(self.AESSupplementKey, self.AESModel, IV) return ''' @fn DataBlock(self, OriginalKey, DataBlockLen, SupplementChar) @brief 对数据进行块化。 @details 数据块必须是128、192、256Bit的倍数。 @param[in] OriginalKey 原始未块化数据。 @param[in] DataBlockLen 块化后数据的长度。 @param[in] SupplementChar 用于填充的字符。 @return 块化后的数据。 @note 无。 @attention 无 ''' def DataBlock(self, OriginalKey, DataBlockLen, SupplementChar): SupplementData = OriginalKey.encode(self.AESEncode) #如果数据不是块长度的整数倍,则对数据进行填充 while len(SupplementData) % DataBlockLen != 0: SupplementData += SupplementChar.encode('utf-8') return SupplementData ''' @fn AESEncrypt(self, OriginalText) @brief AES加密,将明文转化为密文。 @details 需要确保加密的是块化后的数据。 @param[in] OriginalText 原始未块化明文。 @return 密文 @note 无。 @attention 无 ''' def AESEncrypt(self, OriginalText): SupplementText = self.DataBlock(OriginalText, self.AESDataBlockLen, self.SupplementChar) EncryptedText = self.AES.encrypt(SupplementText) return base64.encodebytes(EncryptedText).decode().strip() ''' @fn AESDecrypt(self, DecryptedText) @brief AES解密,将密文转化为明文。 @details 无。 @param[in] DecryptedText 密文。 @return 明文 @note 无。 @attention 无 ''' def AESDecrypt(self, DecryptedText): OriginalText = base64.decodebytes(DecryptedText.encode(self.AESEncode)) OriginalText = self.AES.decrypt(OriginalText) return OriginalText .decode(self.AESEncode).strip('\0')
对特定芯片和固件进行加密时设定AES参数。
''' @file HDSCCrypt.py @brief 固件加密类 @details 创建该对象进行固件加密 @author Calm @data 2020-03-13 @version 1.0.0 @copyright Calm ''' from AESCrypt import * import re class HDSCCrypt: ''' @fn __init__(self) @brief 无参构造函数。 @details 固件使用AES加密的参数在构造函数里设定。 @return None @note 无。 @attention 无 ''' def __init__(self): self.HDSCCryptKey = "123456789" self.HDSCCryptModel = "ECB" self.HDSCCryptIV = "" self.HDSCCryptEncode = "gbk" self.HDSCCryptDataBlockLen = 16 self.AESCrypt = AESCrypt(self.HDSCCryptKey, self.HDSCCryptModel, self.HDSCCryptIV, self.HDSCCryptEncode, self.HDSCCryptDataBlockLen, "\x00") return ''' @fn HDSCEncrypt(self, Plaintext) @brief 计算烧录固件和芯片加密的密钥。 @details 无。 @param[in] Plaintext 明文。 @return 密文 @note 无。 @attention 无 ''' def HDSCEncrypt(self, Plaintext): return self.AESCrypt.AESEncrypt(Plaintext) ''' @fn CheckPlaintext(self, Plaintext) @brief 对明文输入进行格式检查。 @details 限制为不含空白字符的ASCII码。 @param[in] Plaintext 明文。 @return 检查结果 - 0 正确 - 1 含有空白字符 - 2 含有非ASCII码 - 3 空明文 @note 无。 @attention 无 ''' def CheckPlaintext(self, Plaintext): Ret = 0 if re.match('.*\s.*', Plaintext) is not None: #包含空白字符 Ret = 1 elif len(Plaintext) != len(Plaintext.encode('utf-8')): #含有非ASCII码 Ret = 2 elif Plaintext == "": #明文为空 Ret = 3 else: #正确明文 Ret = 0 return Ret
在Windows下构造GUI。这个GUI界面非常简洁,两个编辑框和两个按键,相应的有两个按键的回调函数。
''' @file CryptGUI.py @brief 固件加密软件GUI类 @details 创建该对象进行固件加密GUI生成 @author Calm @data 2020-03-13 @version 1.0.0 @copyright Calm ''' from tkinter import * import tkinter.messagebox from HDSCCrypt import * from IconResourse import Icon import os class CryptGUI: ''' @fn __init__(self, StaticText1, StaticText2, ButtonText1, ButtonText2) @brief 带参构造函数,参数可设置静态文本和按钮文本。 @details 无。 @param[in] StaticText1 静态文本1。 @param[in] StaticText2 静态文本2。 @param[in] ButtonText1 按钮文本1。 @param[in] ButtonText2 按钮文本2。 @return None @note 无。 @attention 无 ''' def __init__(self, StaticText1, StaticText2, ButtonText1, ButtonText2): self.Window = Tk() self.Str1 = StringVar() self.Str2 = StringVar() self.HDSCFirmwareKey = HDSCCrypt() # 对Label进行表格式布局 Label(self.Window, text=StaticText1).grid(row=0, column=0) Label(self.Window, text=StaticText2).grid(row=1, column=0) # 对编辑框进行表格式布局 Edit1 = Entry(self.Window, textvariable=self.Str1, width=32) Edit2 = Entry(self.Window, textvariable=self.Str2, state='readonly', width=32) Edit1.grid(row=0, column=1, padx=10, pady=5) Edit2.grid(row=1, column=1, padx=10, pady=5) Button(self.Window, text=ButtonText1, width=10, command=self.CallBackButton1).grid(row=3, column=0, sticky=W, padx=10, pady=5) Button(self.Window, text=ButtonText2, width=10, command=self.CallBackButton2).grid(row=3, column=1, sticky=E, padx=10, pady=5) ScreenWidth, ScreenHeigh = self.Window.maxsize() CurWidth = self.Window.winfo_reqwidth() CurHeight = self.Window.winfo_reqheight() self.Window.geometry("+{}+{}".format(ScreenWidth // 2 - CurWidth, ScreenHeigh // 2 - CurHeight)) #设置窗口是否可变长、宽,True:可变,False:不可变 self.Window.resizable(width=False, height=False) #图标资源保存在IconResourse.py里,目的是保证生成的exe不依赖其他文件 tmp = open("tmp.icon", "wb+") tmp.write(base64.b64decode(Icon)) #临时图标文件 tmp.close() #修改图标 self.Window.iconbitmap("tmp.icon") os.remove("tmp.icon") #删除临时图标文件 #修改窗口标题 self.Window.title("HDSCCrypt V1.0.0") return ''' @fn CallBackButton1(self) @brief 按钮1回调函数。 @details 读取编辑框1内容进行加密后显示在编辑框2。会对明文格式进行检查。 @return None @note 无。 @attention 无 ''' def CallBackButton1(self): Plaintext = self.Str1.get() self.Str2.set("") CheckResult = self.HDSCFirmwareKey.CheckPlaintext(Plaintext ) if CheckResult == 1: tkinter.messagebox.showinfo('Error', '明文不符合规范\n\n\n错误原因:含有空白字符。') elif CheckResult == 2: tkinter.messagebox.showinfo('Error', '明文不符合规范\n\n\n错误原因:限制只能使用ASCII字符。') elif CheckResult == 3: pass else: Ciphertext = self.HDSCFirmwareKey.HDSCEncrypt(Plaintext) if len(Ciphertext) > 16: Ciphertext = Ciphertext[0:16] self.Str2.set(Ciphertext) return ''' @fn CallBackButton2(self) @brief 按钮2回调函数。 @details 弹出关于对话框,显示描述信息。 @return None @note 无。 @attention 无 ''' def CallBackButton2(self): tkinter.messagebox.showinfo("关于", "使用说明:该软件用于单片机进行芯片和烧录文件加密时,将明文信息转换为密文。如果发现Bug请联系作者。\n\n作者:Calm\n发布日期:2020-03-13\n发布版本:V1.0.0\n版权:Calm") return ''' @fn CryptGUILoopRun(self) @brief 开始对GUI时间监听。 @details 无。 @return None @note 无。 @attention 无 ''' def CryptGUILoopRun(self): mainloop() return
模块封装好后调用就非常简单了。
''' @file main.py @brief 入口文件 @details 无 @author Calm @data 2020-03-13 @version 1.0.0 @copyright Calm ''' from CryptGUI import * ''' @fn main() @brief 入口函数 @details 无 @return None @note 无。 @attention 无 ''' def main(): #创建加密GUI窗口对象 HDSCCryptGUI = CryptGUI("明文: ", "密文: ", "加密", "关于") HDSCCryptGUI.CryptGUILoopRun() return if __name__ == "__main__": main()
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。