芯片AES加密密钥生成工具

芯片AES加密密钥生成工具


前言:嵌入式单片机开发,为了防止别人将芯片内的代码读取出来通过反编译手段拿到源码,常用的手段是对芯片和烧录文件进行加密。大部分的芯片厂商都会提供一个加密烧录和配置文件的工具。这个工具一般需要你填写一定长度的密钥,如果密钥填写得太有规律比如:123456,或项目名+版本号等,这样的密钥对公司来说极度不安全,如果被对手知道别人很可能直接破解出你的源码,然后抄一下你的板就和你一模一样出货了,别人省去了开发成本何乐不为呢?所以本文介绍一种通过AES加密算法将明文转换为密文的工具制作。AES加密算法目前没有破解办法,据我所知微信小程序就用到了这种加密算法。

模块构成

  制作这样的工具只需要三个模块即可完成,AES加密算法模块、芯片加密模块、GUI模块。本文使用Pathon3语言开发。

AES模块

  AES加密是一种常见的对称加密算法,具有较高的安全性。之所以选择用Python3来做这个工具,就是因为其丰富的现成模块支持,没必要重复造轮子,Windows下我们直接导入pycryptodome模块。由于是对称加密其基本形式是明文+密钥=密文密文+密钥=明文
  虽然AES算法不用我们实现,但是其原理和参数需要有一定的了解。实现一次AES运算需要输入密钥、明文、模式、偏移量、字符集类型、数据块、填充内容。输出即是密文。

  • 输入参数:
    • 密钥:因为是对称加密算法,所以加密和解密都需要使用这个密钥参与运算。
    • 明文:需要被加密的字符串,建议限制用ASCII字符。
    • 模式:AES有很多种加密模式,最常用的是ECB和CBC,如果是ECB模式则不需要设置偏移量,如果是CBC模式则需要设置偏移量。
    • 偏移量:偏移量会被带入到加密运算过程中影响加密结果,具体看下算法理论部分就明白了。
    • 字符集类型:输入输出都是文本,需要指明文本类型。
    • 数据块:算法运算原理要求输入的明文和密钥需要是128、192、256Bits的整数倍,也即16、24、32字节的整数倍。
    • 填充内容:上面提到了数据块要求明文和密钥是三种字节的整数倍,如果不是则需要填充一些字符使其成为整数倍这样才能进行AES算法的运算。所以这个参数即是定义填充的字符。
  • 模块内函数:
    • init(self, Key, Model, IV, Encode, DataBlockLen, SupplementChar) 构造函数,输入AES的参数。
    • DataBlock(self, OriginalKey, DataBlockLen, SupplementChar) 对数据(指明文和密钥)进行块化,填充使其为16、24、32字节的整数倍。
    • AESEncrypt(self, OriginalText) 加密函数,将明文转换为密文。
    • AESDecrypt(self, DecryptedText) 解密函数,将密文转换为明文。我们的工具用于加密,所以这个函数实际没被调用,但我还是将其写出了。
'''
@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')

HDSCCrypt模块

  对特定芯片和固件进行加密时设定AES参数。

  • 输入参数:
    • 明文:需要被加密的字符串。
    • 其他参数:其他参数就是上面提到的AES加密需要的参数。
  • 模块内函数:
    • init(self) 构造函数,输入AES加密相关的参数。
    • HDSCEncrypt(self, Plaintext) 针对特定厂商芯片的加密函数,将明文转换为密文。
    • CheckPlaintext(self, Plaintext) 对明问进行格式检查,当含有非ASCII字符或空白时抛出错误码。
'''
@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

CryptGUI模块

  在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()
发布了23 篇原创文章 · 获赞 29 · 访问量 7378

猜你喜欢

转载自blog.csdn.net/qq_42475711/article/details/104934439