AES算法原理和硬件实现

#声明:本文创作内容含代码均为个人创作所得,允许学习、传阅,不得用于商业用途#

#本文包含AES从算法到硬件实现的全部# 

#实践会让你更加透彻理解算法原理,才能让知识灌入大脑#

一 背景:

AES(Advanced Encryption Standard)是对称加密算法中的一种,应用于数据块加密,是美国国家标准与技术提供的一种数据加密算法,目前已成为国际上标准的数据加密算法;AES算法有三种子类型,分贝是AES-128,AES-192,AES-256,区别是加密的密钥长度分别是128bit,192bit,256bit,密钥越长,算法的安全性也越高,但每次加密的数据块的大小均是128bit,AES和国密SM4一样,均是多轮迭代算法,密钥长度越长,迭代次数越多;

AES加密类型
密钥长度数据块大小迭代次数
AES-128128 bit128 bit10
AES-192192 bit128 bit12
AES-256256 bit128 bit14

二 算法说明:

   整个算法迭代过程可以用下面公式来表示:

                                X_{i+1}=F(X_{i} , K_{i})     i =0,1,...,n-1

其中Xi是第i轮迭代的输入,Ki是第i轮迭代扩展后的密钥;F函数特定的逻辑运算;初始值X0为输入的128bit明文,n为迭代的总轮数。

F函数可以用这个公式来表达:F(a,b) = f( g ( h( t(x) ) ), b)

即,每一轮迭代过程分为四个步骤,t,h,g,f。

步骤一 t:字节替换层:

        将输入的128bit,也就是16个字节,每个字节根据查找表替换出对应的字节;比如8bit数字 01001101,对应的16进制为4D,4作为查找表的行,D作为查找表的列,则替换的字节为e3。查找表如下:

再举个例子,输入数据为5a610dc3,则替换后的数据为:be4770eb

步骤二 h:行移位

        把经过字节替换后的128bit依次分为16个字节,{B0,B1,B2... B15};为了更好理解行移位,我们将这16个字节放入到4x4的矩阵中,如下图,

B0       B4     B8B12
B1B5       B9B13
B2B6B10B14
B3B7B11B15

按照以下变换规则:第一行位置不变,第二行循环右移3个格子,第三行循环右移2个格子,第四行循环右移1个格子,得到变换后的矩阵,如下图所示

B0      B4    B7B12
B5B9     B13B1
B10B14B2B6
B15B3B7B11

用公式表示为{B0 B5 B10 B15 B4 B9 B14 B3 B7 B13 B2 B7 B12 B1 B6 B11} = h(B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11 B12 B13 B14 B15)

步骤三 g:列混淆

列混淆是一个线性变换,将矩阵的列给打乱,具体形式是一个矩阵乘法:

                                                       C = P*B                               

其中P系数如下:

02  03   0101
0102   0301
01010203
03010102

B矩阵是步骤二变换后的矩阵,C矩阵排列方式如下表示:

C0   C4   C8C12
C1C5    C9C13
C2C6C10C14
C3C7C11C15

举个例子:C0= 02*B0 + 03*B5 + 01*B10 + 01*B15

这里的加法和乘法是基于伽罗华域(2,8),至于伽罗华域运算,这是另外一个话题,大家可以先参考下其他的资料;这里我们直接给出运算方法:

01 对应的是0000 0001,即多项式f(x) = 1 

02对应的是0000 0010, 即多项式f(x) = x

03 对应的是0000 0100,即多项式f(x) = x^2 = x * x = 02 * 02

我们假设被乘数字节为b,对应的二进制表示为{b7 b6 b5 b4 b3 b2 b1 b0}

      01 * b = b 

      02 * b = {b6 b5 b4 b3 b2 b1 0}  ,若b7=0

      02 * b = {b6 b5 b4 b3 b2 b1 0} ^ {0 0 0 1 1 0 1 1} ,若b7=1

      03 * b = 02 * 02* b = 02*(02 * b);需要经过两次迭代

步骤四 f:密钥加法层

密钥加法层就是将第三步的输出结果和当前轮的密钥直接异或

                                即  f(a,b) = a ^ b         其中a b均为128bit

下图表示的一轮迭代过程:

AES整体的架构如下图:

注意:第一轮迭代前,先进行密钥加法运算,最后一轮迭代少了列混淆运算

 密钥迭代方法:

密钥函数迭代相对来说简单点, 公式如下:

                                        K_{n+1}[0]=K_{n}[0] \oplus g(K_{n}[3])

                                        K{n+1}[1]=K_{n+1}[0] \oplus K_{n}[1]

                        ​​​​​​​        ​​​​​​​        K_{n+1}[2]=K_{n+1}[1] \oplus K_{n}[2]

                                        K_{n+1}[3]=K_{n+1}[2] \oplus K_{n}[3]               

 公式中n指的是迭代的轮数,[]是密钥字索引,g()是一个逻辑运算,配合下图可能更容易理解

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​      

那图片中的g()函数表现形式是啥呢?

 g函数的输入是32bit 用V来表示,也就是4个字节,我们用 V0,V1,V2,V3来表示,

g函数主要分为3个操作,第一步移位,V<<<8,V向左循环移位8位;第二位查找表替换,也就是将第一步得到的4个字节从查找表中得到对应的4个字节;第三步将第二步中得到第一个字节和数字n(8bit)异或,n当前迭代的轮数的gf(2,8)的八位二级制数;这里的密钥查找表和密文迭代的查找表一样

g函数架构如下图所示:

        ​​​​​​​        ​​​​​​​        ​​​​​​​        

以上就是AES-128算法的所有过程;AES-196和AES-256迭代过程与128稍有不过,主要是密钥迭代和轮数

AES-196:由于其密钥长度为196,密钥迭代的公式多了一个K[4],

                                        K_{n+1}[4]=K_{n+1}[3] \oplus K_{n}[4]

AES-256:由于其密钥长度为256,密钥迭代的公式多了K[4],K[5],K[6],K[7]

                                        K_{n+1}[4]=h(K_{n+1}[3]) \oplus K_{n}[4]

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        K_{n+1}[5]=K_{n+1}[4] \oplus K_{n}[5]

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        K_{n+1}[6]=K_{n+1}[5] \oplus K_{n}[6]

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        K_{n+1}[7]=K_{n+1}[6] \oplus K_{n}[7]

上诉公式中 h() 为32bit经过查找表替换

为了统一三种不同格式,我们在密钥迭代中,先迭代出所有密钥,然后将其拼起来。在每一轮明文迭代中依次取四个字(一共128bit),这样就可以保证不需要针对不同类型,开发出不同算法;

算法讲解就到这里,下面我们用python来实现其功能

三 python实现

--------今天就先到这里,快晚上12点了,打一局王者睡觉,明天还得上班-----------

我来更新代码了

该代码支持AES-128,AES-196,  AES-256 三种模式

大家在代码中输入明文和密文的位宽要符合规定,否者会跑不通

大家在手动敲查找表的时候,一定要注意,我就因为这个浪费了点时间;由于代码中名字有点随意,大家结合算法原理来看:

class AesEncryption:

    TABLE = {'00': '63', '01': '7c', '02': '77', '03': '7b', '04': 'f2', '05': '6b', '06': '6f', '07': 'c5',
             '08': '30', '09': '01', '0a': '67', '0b': '2b', '0c': 'fe', '0d': 'd7', '0e': 'ab', '0f': '76',

             '10': 'ca', '11': '82', '12': 'c9', '13': '7d', '14': 'fa', '15': '59', '16': '47', '17': 'f0',
             '18': 'ad', '19': 'd4', '1a': 'a2', '1b': 'af', '1c': '9c', '1d': 'a4', '1e': '72', '1f': 'c0',

             '20': 'b7', '21': 'fd', '22': '93', '23': '26', '24': '36', '25': '3f', '26': 'f7', '27': 'cc',
             '28': '34', '29': 'a5', '2a': 'e5', '2b': 'f1', '2c': '71', '2d': 'd8', '2e': '31', '2f': '15',

             '30': '04', '31': 'c7', '32': '23', '33': 'c3', '34': '18', '35': '96', '36': '05', '37': '9a',
             '38': '07', '39': '12', '3a': '80', '3b': 'e2', '3c': 'eb', '3d': '27', '3e': 'b2', '3f': '75',

             '40': '09', '41': '83', '42': '2c', '43': '1a', '44': '1b', '45': '6e', '46': '5a', '47': 'a0',
             '48': '52', '49': '3b', '4a': 'd6', '4b': '83', '4c': '29', '4d': 'e3', '4e': '2f', '4f': '84',

             '50': '53', '51': 'd1', '52': '00', '53': 'ed', '54': '20', '55': 'fc', '56': 'b1', '57': '5b',
             '58': '6a', '59': 'cb', '5a': 'be', '5b': '39', '5c': '4a', '5d': '4c', '5e': '58', '5f': 'cf',

             '60': 'd0', '61': 'ef', '62': 'aa', '63': 'fb', '64': '43', '65': '4d', '66': '33', '67': '85',
             '68': '45', '69': 'f9', '6a': '02', '6b': '7f', '6c': '50', '6d': '3c', '6e': '9f', '6f': 'a8',

             '70': '51', '71': 'a3', '72': '40', '73': '8f', '74': '92', '75': '9d', '76': '38', '77': 'f5',
             '78': 'bc', '79': 'b6', '7a': 'da', '7b': '21', '7c': '10', '7d': 'ff', '7e': 'f3', '7f': 'd2',

             '80': 'cd', '81': '0c', '82': '13', '83': 'ec', '84': '5f', '85': '97', '86': '44', '87': '17',
             '88': 'c4', '89': 'a7', '8a': '7e', '8b': '3d', '8c': '64', '8d': '5d', '8e': '19', '8f': '73',

             '90': '60', '91': '81', '92': '4f', '93': 'dc', '94': '22', '95': '2a', '96': '90', '97': '88',
             '98': '46', '99': 'ee', '9a': 'b8', '9b': '14', '9c': 'de', '9d': '5e', '9e': '0b', '9f': 'db',

             'a0': 'e0', 'a1': '32', 'a2': '3a', 'a3': '0a', 'a4': '49', 'a5': '06', 'a6': '24', 'a7': '5c',
             'a8': 'c2', 'a9': 'd3', 'aa': 'ac', 'ab': '62', 'ac': '91', 'ad': '95', 'ae': 'e4', 'af': '79',

             'b0': 'e7', 'b1': 'c8', 'b2': '37', 'b3': '6d', 'b4': '8d', 'b5': 'd5', 'b6': '4e', 'b7': 'a9',
             'b8': '6c', 'b9': '56', 'ba': 'f4', 'bb': 'ea', 'bc': '65', 'bd': '7a', 'be': 'ae', 'bf': '08',

             'c0': 'ba', 'c1': '78', 'c2': '25', 'c3': '2e', 'c4': '1c', 'c5': 'a6', 'c6': 'b4', 'c7': 'c6',
             'c8': 'e8', 'c9': 'dd', 'ca': '74', 'cb': '1f', 'cc': '4b', 'cd': 'bd', 'ce': '8b', 'cf': '8a',

             'd0': '70', 'd1': '3e', 'd2': 'b5', 'd3': '66', 'd4': '48', 'd5': '03', 'd6': 'f6', 'd7': '0e',
             'd8': '61', 'd9': '35', 'da': '57', 'db': 'b9', 'dc': '86', 'dd': 'c1', 'de': '1d', 'df': '9e',

             'e0': 'e1', 'e1': 'f8', 'e2': '98', 'e3': '11', 'e4': '69', 'e5': 'd9', 'e6': '8e', 'e7': '94',
             'e8': '9b', 'e9': '1e', 'ea': '87', 'eb': 'e9', 'ec': 'ce', 'ed': '55', 'ee': '28', 'ef': 'df',

             'f0': '8c', 'f1': 'a1', 'f2': '89', 'f3': '0d', 'f4': 'bf', 'f5': 'e6', 'f6': '42', 'f7': '68',
             'f8': '41', 'f9': '99', 'fa': '2d', 'fb': '0f', 'fc': 'b0', 'fd': '54', 'fe': 'bb', 'ff': '16'}

    GF_8 = {1: '01', 2: '02', 3: '04', 4: '08', 5: '10', 6: '20', 7: '40', 8: '80', 9: '1b', 10: '36'}

    def gf_01(self,x):
        return x
    def gf_02(self,x):
        num = int(x,16) & 0xFF
        flag = num & 0x80
        y = 0
        if (flag) :
            y = ((num << 1) & 0xFF) ^ 0x1b
        else:
            y = (num << 1) & 0xFF
        return '{:02x}'.format(y)

    def gf_03(self,x):
        y0 = int(self.gf_01(x),16) & 0xFF
        y1 = int(self.gf_02(x),16) & 0xFF
        return '{:02x}'.format(y0 ^ y1)

    def sub_byte(self, x):
        y = ''
        for i in range(4):
            y = y + self.TABLE[x[2*i:2*i+2]]
        return y

    def shift_row(self, x):
        y = [''] * 4
        y[0] = x[0:2] + x[10:12] + x[20:22] + x[30:32]
        y[1] = x[8:10] + x[18:20] + x[28:30] + x[6:8]
        y[2] = x[16:18] + x[26:28] + x[4:6] + x[14:16]
        y[3] = x[24:26] + x[2:4] + x[12:14] + x[22:24]
        return y

    def mix_columns(self, x):
        y0 = int(self.gf_02(x[0:2]), 16) ^ int(self.gf_03(x[2:4]), 16) ^ int(self.gf_01(x[4:6]), 16) ^ int(self.gf_01(x[6:8]), 16) & 0xFF
        y0_str = '{:02x}'.format(y0)
        y1 = int(self.gf_01(x[0:2]), 16) ^ int(self.gf_02(x[2:4]), 16) ^ int(self.gf_03(x[4:6]), 16) ^ int(self.gf_01(x[6:8]), 16) & 0xFF
        y1_str = '{:02x}'.format(y1)
        y2 = int(self.gf_01(x[0:2]), 16) ^ int(self.gf_01(x[2:4]), 16) ^ int(self.gf_02(x[4:6]), 16) ^ int(self.gf_03(x[6:8]), 16) & 0xFF
        y2_str = '{:02x}'.format(y2)
        y3 = int(self.gf_03(x[0:2]), 16) ^ int(self.gf_01(x[2:4]), 16) ^ int(self.gf_01(x[4:6]), 16) ^ int(self.gf_02(x[6:8]), 16) & 0xFF
        y3_str = '{:02x}'.format(y3)

        y4 = int(self.gf_02(x[8:10]), 16) ^ int(self.gf_03(x[10:12]), 16) ^ int(self.gf_01(x[12:14]), 16) ^ int(self.gf_01(x[14:16]), 16) & 0xFF
        y4_str = '{:02x}'.format(y4)
        y5 = int(self.gf_01(x[8:10]), 16) ^ int(self.gf_02(x[10:12]), 16) ^ int(self.gf_03(x[12:14]), 16) ^ int(self.gf_01(x[14:16]), 16) & 0xFF
        y5_str = '{:02x}'.format(y5)
        y6 = int(self.gf_01(x[8:10]), 16) ^ int(self.gf_01(x[10:12]), 16) ^ int(self.gf_02(x[12:14]), 16) ^ int(self.gf_03(x[14:16]), 16) & 0xFF
        y6_str = '{:02x}'.format(y6)
        y7 = int(self.gf_03(x[8:10]), 16) ^ int(self.gf_01(x[10:12]), 16) ^ int(self.gf_01(x[12:14]), 16) ^ int(self.gf_02(x[14:16]), 16) & 0xFF
        y7_str = '{:02x}'.format(y7)

        y8 = int(self.gf_02(x[16:18]), 16) ^ int(self.gf_03(x[18:20]), 16) ^ int(self.gf_01(x[20:22]), 16) ^ int(self.gf_01(x[22:24]), 16) & 0xFF
        y8_str = '{:02x}'.format(y8)
        y9 = int(self.gf_01(x[16:18]), 16) ^ int(self.gf_02(x[18:20]), 16) ^ int(self.gf_03(x[20:22]), 16) ^ int(self.gf_01(x[22:24]), 16) & 0xFF
        y9_str = '{:02x}'.format(y9)
        y10 = int(self.gf_01(x[16:18]), 16) ^ int(self.gf_01(x[18:20]), 16) ^ int(self.gf_02(x[20:22]), 16) ^ int(self.gf_03(x[22:24]), 16) & 0xFF
        y10_str = '{:02x}'.format(y10)
        y11 = int(self.gf_03(x[16:18]), 16) ^ int(self.gf_01(x[18:20]), 16) ^ int(self.gf_01(x[20:22]), 16) ^ int(self.gf_02(x[22:24]), 16) & 0xFF
        y11_str = '{:02x}'.format(y11)

        y12 = int(self.gf_02(x[24:26]), 16) ^ int(self.gf_03(x[26:28]), 16) ^ int(self.gf_01(x[28:30]), 16) ^ int(self.gf_01(x[30:32]), 16) & 0xFF
        y12_str = '{:02x}'.format(y12)
        y13 = int(self.gf_01(x[24:26]), 16) ^ int(self.gf_02(x[26:28]), 16) ^ int(self.gf_03(x[28:30]), 16) ^ int(self.gf_01(x[30:32]), 16) & 0xFF
        y13_str = '{:02x}'.format(y13)
        y14 = int(self.gf_01(x[24:26]), 16) ^ int(self.gf_01(x[26:28]), 16) ^ int(self.gf_02(x[28:30]), 16) ^ int(self.gf_03(x[30:32]), 16) & 0xFF
        y14_str = '{:02x}'.format(y14)
        y15 = int(self.gf_03(x[24:26]), 16) ^ int(self.gf_01(x[26:28]), 16) ^ int(self.gf_01(x[28:30]), 16) ^ int(self.gf_02(x[30:32]), 16) & 0xFF
        y15_str = '{:02x}'.format(y15)

        y = ['']*4
        y[0] = y0_str + y1_str + y2_str + y3_str
        y[1] = y4_str + y5_str + y6_str + y7_str
        y[2] = y8_str + y9_str + y10_str + y11_str
        y[3] = y12_str + y13_str + y14_str + y15_str

        return y
 
    def add_round_key(self, x, key):
        x0 = int(x[0], 16) ^ int(key[0], 16) & 0xFFFFFFFF
        x0_str = '{:08x}'.format(x0)
        x1 = int(x[1], 16) ^ int(key[1], 16) & 0xFFFFFFFF
        x1_str = '{:08x}'.format(x1)
        x2 = int(x[2], 16) ^ int(key[2], 16) & 0xFFFFFFFF
        x2_str = '{:08x}'.format(x2)
        x3 = int(x[3], 16) ^ int(key[3], 16) & 0xFFFFFFFF
        x3_str = '{:08x}'.format(x3)
        return [x0_str , x1_str , x2_str , x3_str]

    def key_g_function(self, x, i):
        if i<= 10:
            rn = self.GF_8[i]
        else:
            rn = '00'
        tmp = int(self.TABLE[x[2:4]], 16) ^ int(rn, 16) & 0xFF
        return '{:02x}'.format(tmp) + self.TABLE[x[4:6]] + self.TABLE[x[6:8]] + self.TABLE[x[0:2]]

    def key_h_function(self, x):
        return self.TABLE[x[0:2]] + self.TABLE[x[2:4]] + self.TABLE[x[4:6]] + self.TABLE[x[6:8]]

    def key_round(self, x, mode):
        if mode == 0:
            round_num = 10
            key_len   = 4  # 4 word  ---32bit
        elif mode == 1:
            round_num = 12
            key_len   = 6
        else:
            round_num = 14
            key_len   = 8

        y = [''] * key_len
        key = [''] * key_len * (round_num+1)
        for i in range(key_len):
            key[i] = x[8*i:8*(i+1)]

        for i in range(1, round_num+1):
            for j in range(key_len):
                if j == 0:
                    key[i* key_len + j] = '{:08x}'.format(int(key[(i-1)* key_len], 16) ^ int(self.key_g_function(key[i*key_len+j-1],i), 16) & 0xFFFFFFFF)
                elif ((j == 4) & (mode == 2)):
                    key[i * key_len + j] = '{:08x}'.format(int(self.key_h_function(key[i * key_len + j - 1]), 16) ^ int(key[(i - 1) * key_len + j], 16) & 0xFFFFFFFF)
                else:
                    key[i* key_len + j] = '{:08x}'.format(int(key[i* key_len + j -1], 16) ^ int(key[(i-1)* key_len+j], 16) & 0xFFFFFFFF)
                #print(i*key_len+j, key[i* key_len + j])
        for i in range(len(key)):
            print(i, key[i])
        return key

    def encryption_iteration(self, x, key, mode):
        if mode == 0:
            round_num = 10
            key_len = 4  # 4 word  ---32bit
        elif mode == 1:
            round_num = 12
            key_len = 6
        else:
            round_num = 14
            key_len = 8

        y = [''] * 4
        for i in range(4):
            y[i] = x[i*8:i*8+8]

        key_list = self.key_round(key, mode)

        y = self.add_round_key(y, key_list[0:key_len])   # pre add key
        for i in range(round_num-1):
            print(i,y)
            for j in range(4):
                y[j] = self.sub_byte(y[j])
            y = self.shift_row(y[0]+y[1]+y[2]+y[3])
            y = self.mix_columns(y[0]+y[1]+y[2]+y[3])
            y = self.add_round_key(y, key_list[4*(i+1):4*(i+1)+4])

        for j in range(4):
            y[j] = self.sub_byte(y[j])
        y = self.shift_row(y[0] + y[1] + y[2] + y[3])
        y = self.add_round_key(y, key_list[4 * round_num:4 * round_num + 4])

        return y

if __name__ == '__main__':
    get_class = AesEncryption()
    output = get_class.encryption_iteration('3243f6a8885a308d313198a2e0370734', '2b7e151628aed2a6abf7158809cf4f3c',0)

    # output = get_class.encryption_iteration('3243f6a8885a308d313198a2e0370734', '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b', 1)

    # output = get_class.encryption_iteration('3243f6a8885a308d313198a2e0370734',
                                            '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4', 2)
    print(output)

四 Verilog硬件实现

Verilog考虑的比较多,还需要验证,后续等休假我来统一补充

  • 39
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值