3DES加密算法Python实现

目前网上使用Python实现的DES算法,绝大部分是用原始的PC表、置换表E、S盒实现加解密计算的。这里给出另外一个更接近DES算法反编译后的版本。

本文算法是根据此处链接的javascript改写的。

from struct import pack


class DES():
    def __init__(self, key):
        self.sub_keys = self.create_keys(key)

    def encrypt(self, message, mode="ECB", iv=None, padding=1):
        return self.crypt(message, 1, mode, iv, padding)

    def decrypt(self, message, mode="ECB", iv=None, padding=1):
        return self.crypt(message, 0, mode, iv, padding)

    def crypt(self, message, encrypt, mode, iv, padding):
        spfunction1 = [0x1010400, 0, 0x10000, 0x1010404, 0x1010004, 0x10404, 0x4, 0x10000, 0x400, 0x1010400, 0x1010404, 0x400, 0x1000404, 0x1010004, 0x1000000, 0x4, 0x404, 0x1000400, 0x1000400, 0x10400, 0x10400, 0x1010000, 0x1010000, 0x1000404, 0x10004, 0x1000004, 0x1000004, 0x10004, 0, 0x404, 0x10404, 0x1000000, 0x10000, 0x1010404, 0x4, 0x1010000, 0x1010400, 0x1000000, 0x1000000, 0x400, 0x1010004, 0x10000, 0x10400, 0x1000004, 0x400, 0x4, 0x1000404, 0x10404, 0x1010404, 0x10004, 0x1010000, 0x1000404, 0x1000004, 0x404, 0x10404, 0x1010400, 0x404, 0x1000400, 0x1000400, 0, 0x10004, 0x10400, 0, 0x1010004]
        spfunction2 = [0x80108020, 0x80008000, 0x8000, 0x108020, 0x100000, 0x20, 0x80100020, 0x80008020, 0x80000020, 0x80108020, 0x80108000, 0x80000000, 0x80008000, 0x100000, 0x20, 0x80100020, 0x108000, 0x100020, 0x80008020, 0, 0x80000000, 0x8000, 0x108020, 0x80100000, 0x100020, 0x80000020, 0, 0x108000, 0x8020, 0x80108000, 0x80100000, 0x8020, 0, 0x108020, 0x80100020, 0x100000, 0x80008020, 0x80100000, 0x80108000, 0x8000, 0x80100000, 0x80008000, 0x20, 0x80108020, 0x108020, 0x20, 0x8000, 0x80000000, 0x8020, 0x80108000, 0x100000, 0x80000020, 0x100020, 0x80008020, 0x80000020, 0x100020, 0x108000, 0, 0x80008000, 0x8020, 0x80000000, 0x80100020, 0x80108020, 0x108000]
        spfunction3 = [0x208, 0x8020200, 0, 0x8020008, 0x8000200, 0, 0x20208, 0x8000200, 0x20008, 0x8000008, 0x8000008, 0x20000, 0x8020208, 0x20008, 0x8020000, 0x208, 0x8000000, 0x8, 0x8020200, 0x200, 0x20200, 0x8020000, 0x8020008, 0x20208, 0x8000208, 0x20200, 0x20000, 0x8000208, 0x8, 0x8020208, 0x200, 0x8000000, 0x8020200, 0x8000000, 0x20008, 0x208, 0x20000, 0x8020200, 0x8000200, 0, 0x200, 0x20008, 0x8020208, 0x8000200, 0x8000008, 0x200, 0, 0x8020008, 0x8000208, 0x20000, 0x8000000, 0x8020208, 0x8, 0x20208, 0x20200, 0x8000008, 0x8020000, 0x8000208, 0x208, 0x8020000, 0x20208, 0x8, 0x8020008, 0x20200]
        spfunction4 = [0x802001, 0x2081, 0x2081, 0x80, 0x802080, 0x800081, 0x800001, 0x2001, 0, 0x802000, 0x802000, 0x802081, 0x81, 0, 0x800080, 0x800001, 0x1, 0x2000, 0x800000, 0x802001, 0x80, 0x800000, 0x2001, 0x2080, 0x800081, 0x1, 0x2080, 0x800080, 0x2000, 0x802080, 0x802081, 0x81, 0x800080, 0x800001, 0x802000, 0x802081, 0x81, 0, 0, 0x802000, 0x2080, 0x800080, 0x800081, 0x1, 0x802001, 0x2081, 0x2081, 0x80, 0x802081, 0x81, 0x1, 0x2000, 0x800001, 0x2001, 0x802080, 0x800081, 0x2001, 0x2080, 0x800000, 0x802001, 0x80, 0x800000, 0x2000, 0x802080]
        spfunction5 = [0x100, 0x2080100, 0x2080000, 0x42000100, 0x80000, 0x100, 0x40000000, 0x2080000, 0x40080100, 0x80000, 0x2000100, 0x40080100, 0x42000100, 0x42080000, 0x80100, 0x40000000, 0x2000000, 0x40080000, 0x40080000, 0, 0x40000100, 0x42080100, 0x42080100, 0x2000100, 0x42080000, 0x40000100, 0, 0x42000000, 0x2080100, 0x2000000, 0x42000000, 0x80100, 0x80000, 0x42000100, 0x100, 0x2000000, 0x40000000, 0x2080000, 0x42000100, 0x40080100, 0x2000100, 0x40000000, 0x42080000, 0x2080100, 0x40080100, 0x100, 0x2000000, 0x42080000, 0x42080100, 0x80100, 0x42000000, 0x42080100, 0x2080000, 0, 0x40080000, 0x42000000, 0x80100, 0x2000100, 0x40000100, 0x80000, 0, 0x40080000, 0x2080100, 0x40000100]
        spfunction6 = [0x20000010, 0x20400000, 0x4000, 0x20404010, 0x20400000, 0x10, 0x20404010, 0x400000, 0x20004000, 0x404010, 0x400000, 0x20000010, 0x400010, 0x20004000, 0x20000000, 0x4010, 0, 0x400010, 0x20004010, 0x4000, 0x404000, 0x20004010, 0x10, 0x20400010, 0x20400010, 0, 0x404010, 0x20404000, 0x4010, 0x404000, 0x20404000, 0x20000000, 0x20004000, 0x10, 0x20400010, 0x404000, 0x20404010, 0x400000, 0x4010, 0x20000010, 0x400000, 0x20004000, 0x20000000, 0x4010, 0x20000010, 0x20404010, 0x404000, 0x20400000, 0x404010, 0x20404000, 0, 0x20400010, 0x10, 0x4000, 0x20400000, 0x404010, 0x4000, 0x400010, 0x20004010, 0, 0x20404000, 0x20000000, 0x400010, 0x20004010]
        spfunction7 = [0x200000, 0x4200002, 0x4000802, 0, 0x800, 0x4000802, 0x200802, 0x4200800, 0x4200802, 0x200000, 0, 0x4000002, 0x2, 0x4000000, 0x4200002, 0x802, 0x4000800, 0x200802, 0x200002, 0x4000800, 0x4000002, 0x4200000, 0x4200800, 0x200002, 0x4200000, 0x800, 0x802, 0x4200802, 0x200800, 0x2, 0x4000000, 0x200800, 0x4000000, 0x200800, 0x200000, 0x4000802, 0x4000802, 0x4200002, 0x4200002, 0x2, 0x200002, 0x4000000, 0x4000800, 0x200000, 0x4200800, 0x802, 0x200802, 0x4200800, 0x802, 0x4000002, 0x4200802, 0x4200000, 0x200800, 0, 0x2, 0x4200802, 0, 0x200802, 0x4200000, 0x800, 0x4000002, 0x4000800, 0x800, 0x200002]
        spfunction8 = [0x10001040, 0x1000, 0x40000, 0x10041040, 0x10000000, 0x10001040, 0x40, 0x10000000, 0x40040, 0x10040000, 0x10041040, 0x41000, 0x10041000, 0x41040, 0x1000, 0x40, 0x10040000, 0x10000040, 0x10001000, 0x1040, 0x41000, 0x40040, 0x10040040, 0x10041000, 0x1040, 0, 0, 0x10040040, 0x10000040, 0x10001000, 0x41040, 0x40000, 0x41040, 0x40000, 0x10041000, 0x1000, 0x40, 0x10040040, 0x1000, 0x41040, 0x10001000, 0x40, 0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x40000, 0x10001040, 0, 0x10041040, 0x40040, 0x10000040, 0x10040000, 0x10001000, 0x10001040, 0, 0x10041040, 0x41000, 0x41000, 0x1040, 0x1040, 0x40040, 0x10000000, 0x10041000]

        chunk, m, n, i, j, temp1, temp2, right1, right2, left, right, length = 0, 0, len(self.sub_keys), 0, 0, 0, 0, 0, 0, 0, 0, len(message)
        iterations = 3 if n == 32 else 9

        if iterations == 3:
            looping = (0, 32, 2) if encrypt == 1 else (30, -2, -2)
        else:
            looping = (0, 32, 2, 62, 30, -2, 64, 96, 2) if encrypt == 1 else (94, 62, -2, 32, 64, 2, 30, -2, -2)

        if encrypt == 1:
            padding_length = 8 - (length % 8)
            if padding == 1:
                message = b'%s%s' % (message, chr(padding_length).encode() * padding_length)
            elif padding == 2:
                message = b'%s%s' % (message, b' ' * padding_length)
            else:
                message = b'%s%s' % (message, b'\x00' * padding_length)

        result = b""
        tempresult = b""

        cbcleft, cbcright, cbcleft2, cbcright2 = 0, 0, 0, 0
        if mode.upper() == "CBC" and iv and len(iv) == 8:
            cbcleft = (iv[0] << 24 | iv[1] << 16 | iv[2] << 8 | iv[3]) & 0xffffffff
            cbcright = (iv[4] << 24 | iv[5] << 16 | iv[6] << 8 | iv[7]) & 0xffffffff

        while m < length:
            left = (message[m] << 24 | message[m + 1] << 16 | message[m + 2] << 8 | message[m + 3]) & 0xffffffff
            right = (message[m + 4] << 24 | message[m + 5] << 16 | message[m + 6] << 8 | message[m + 7]) & 0xffffffff
            m += 8

            if mode.upper() == "CBC" and iv and len(iv) == 8:
                if encrypt == 1:
                    left ^= cbcleft
                    right ^= cbcright
                else:
                    cbcleft2 = cbcleft
                    cbcright2 = cbcright
                    cbcleft = left
                    cbcright = right

            temp = ((left >> 4) ^ right) & 0x0f0f0f0f
            right ^= temp
            left ^= (temp << 4) & 0xffffffff

            temp = ((left >> 16) ^ right) & 0x0000ffff
            right ^= temp
            left ^= (temp << 16) & 0xffffffff

            temp = ((right >> 2) ^ left) & 0x33333333
            left ^= temp
            right ^= (temp << 2) & 0xffffffff

            temp = ((right >> 8) ^ left) & 0x00ff00ff
            left ^= temp
            right ^= (temp << 8) & 0xffffffff

            temp = ((left >> 1) ^ right) & 0x55555555
            right ^= temp
            left ^= (temp << 1) & 0xffffffff

            left = ((left << 1) | (left >> 31)) & 0xffffffff
            right = ((right << 1) | (right >> 31)) & 0xffffffff
            for j in range(0, iterations, 3):
                endloop = looping[j + 1]
                loopinc = looping[j + 2]

                i = looping[j]
                while i != endloop:
                    right1 = right ^ self.sub_keys[i]
                    right2 = (((right >> 4) | (right << 28)) ^ self.sub_keys[i + 1]) & 0xffffffff

                    temp = left
                    left = right
                    right = temp ^ (
                        spfunction2[(right1 >> 24) & 0x3f] |
                        spfunction4[(right1 >> 16) & 0x3f] |
                        spfunction6[(right1 >> 8) & 0x3f] |
                        spfunction8[right1 & 0x3f] |
                        spfunction1[(right2 >> 24) & 0x3f] |
                        spfunction3[(right2 >> 16) & 0x3f] |
                        spfunction5[(right2 >> 8) & 0x3f] |
                        spfunction7[right2 & 0x3f])
                    i += loopinc

                temp = left
                left = right
                right = temp

            left = ((left >> 1) | (left << 31)) & 0xffffffff
            right = ((right >> 1) | (right << 31)) & 0xffffffff

            temp = ((left >> 1) ^ right) & 0x55555555
            right ^= temp
            left ^= (temp << 1) & 0xffffffff
            temp = ((right >> 8) ^ left) & 0x00ff00ff
            left ^= temp
            right ^= (temp << 8) & 0xffffffff
            temp = ((right >> 2) ^ left) & 0x33333333
            left ^= temp
            right ^= (temp << 2) & 0xffffffff
            temp = ((left >> 16) ^ right) & 0x0000ffff
            right ^= temp
            left ^= (temp << 16) & 0xffffffff
            temp = ((left >> 4) ^ right) & 0x0f0f0f0f
            right ^= temp
            left ^= (temp << 4) & 0xffffffff

            if mode.upper() == "CBC" and iv and len(iv) == 8:
                if encrypt == 1:
                    cbcleft = left
                    cbcright = right
                else:
                    left ^= cbcleft2
                    right ^= cbcright2

            tempresult += pack("BBBBBBBB", (left >> 24), ((left >> 16) & 0xff),
                ((left >> 8) & 0xff), (left & 0xff), (right >> 24),
                ((right >> 16) & 0xff), ((right >> 8) & 0xff), (right & 0xff))

            chunk += 8
            if chunk == 512:
                result += tempresult
                tempresult = b""
                chunk = 0

        result = b'%s%s' % (result, tempresult)
        if encrypt == 0 and padding:
            pad_len = result[-1]
            end_idx = len(result) - pad_len
            result = result[:end_idx]
        return result

    def create_keys(self, key):
        pc2bytes0 = (0, 0x4, 0x20000000, 0x20000004, 0x10000, 0x10004, 0x20010000, 0x20010004, 0x200, 0x204, 0x20000200, 0x20000204, 0x10200, 0x10204, 0x20010200, 0x20010204)
        pc2bytes1 = (0, 0x1, 0x100000, 0x100001, 0x4000000, 0x4000001, 0x4100000, 0x4100001, 0x100, 0x101, 0x100100, 0x100101, 0x4000100, 0x4000101, 0x4100100, 0x4100101)
        pc2bytes2 = (0, 0x8, 0x800, 0x808, 0x1000000, 0x1000008, 0x1000800, 0x1000808, 0, 0x8, 0x800, 0x808, 0x1000000, 0x1000008, 0x1000800, 0x1000808)
        pc2bytes3 = (0, 0x200000, 0x8000000, 0x8200000, 0x2000, 0x202000, 0x8002000, 0x8202000, 0x20000, 0x220000, 0x8020000, 0x8220000, 0x22000, 0x222000, 0x8022000, 0x8222000)
        pc2bytes4 = (0, 0x40000, 0x10, 0x40010, 0, 0x40000, 0x10, 0x40010, 0x1000, 0x41000, 0x1010, 0x41010, 0x1000, 0x41000, 0x1010, 0x41010)
        pc2bytes5 = (0, 0x400, 0x20, 0x420, 0, 0x400, 0x20, 0x420, 0x2000000, 0x2000400, 0x2000020, 0x2000420, 0x2000000, 0x2000400, 0x2000020, 0x2000420)
        pc2bytes6 = (0, 0x10000000, 0x80000, 0x10080000, 0x2, 0x10000002, 0x80002, 0x10080002, 0, 0x10000000, 0x80000, 0x10080000, 0x2, 0x10000002, 0x80002, 0x10080002)
        pc2bytes7 = (0, 0x10000, 0x800, 0x10800, 0x20000000, 0x20010000, 0x20000800, 0x20010800, 0x20000, 0x30000, 0x20800, 0x30800, 0x20020000, 0x20030000, 0x20020800, 0x20030800)
        pc2bytes8 = (0, 0x40000, 0, 0x40000, 0x2, 0x40002, 0x2, 0x40002, 0x2000000, 0x2040000, 0x2000000, 0x2040000, 0x2000002, 0x2040002, 0x2000002, 0x2040002)
        pc2bytes9 = (0, 0x10000000, 0x8, 0x10000008, 0, 0x10000000, 0x8, 0x10000008, 0x400, 0x10000400, 0x408, 0x10000408, 0x400, 0x10000400, 0x408, 0x10000408)
        pc2bytes10 = (0, 0x20, 0, 0x20, 0x100000, 0x100020, 0x100000, 0x100020, 0x2000, 0x2020, 0x2000, 0x2020, 0x102000, 0x102020, 0x102000, 0x102020)
        pc2bytes11 = (0, 0x1000000, 0x200, 0x1000200, 0x200000, 0x1200000, 0x200200, 0x1200200, 0x4000000, 0x5000000, 0x4000200, 0x5000200, 0x4200000, 0x5200000, 0x4200200, 0x5200200)
        pc2bytes12 = (0, 0x1000, 0x8000000, 0x8001000, 0x80000, 0x81000, 0x8080000, 0x8081000, 0x10, 0x1010, 0x8000010, 0x8001010, 0x80010, 0x81010, 0x8080010, 0x8081010)
        pc2bytes13 = (0, 0x4, 0x100, 0x104, 0, 0x4, 0x100, 0x104, 0x1, 0x5, 0x101, 0x105, 0x1, 0x5, 0x101, 0x105)

        iterations = 3 if len(key) > 8 else 1
        keys = [0] * (32 * iterations)
        shifts = (0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0)

        m, n = 0, 0
        for j in range(0, iterations):
            left = (key[m] << 24 | key[m + 1] << 16 | key[m + 2] << 8 | key[m + 3]) & 0xffffffff
            right = (key[m + 4] << 24 | key[m + 5] << 16 | key[m + 6] << 8 | key[m + 7]) & 0xffffffff
            m += 8

            temp = ((left >> 4) ^ right) & 0x0f0f0f0f
            right ^= temp
            left ^= (temp << 4) & 0xffffffff

            temp = ((right >> 16) ^ left) & 0x0000ffff
            left ^= temp
            right ^= (temp << 16) & 0xffffffff

            temp = ((left >> 2) ^ right) & 0x33333333
            right ^= temp
            left ^= (temp << 2) & 0xffffffff

            temp = ((right >> 16) ^ left) & 0x0000ffff
            left ^= temp
            right ^= (temp << 16) & 0xffffffff

            temp = ((left >> 1) ^ right) & 0x55555555
            right ^= temp
            left ^= (temp << 1) & 0xffffffff

            temp = ((right >> 8) ^ left) & 0x00ff00ff
            left ^= temp
            right ^= (temp << 8) & 0xffffffff

            temp = ((left >> 1) ^ right) & 0x55555555
            right ^= temp
            left ^= (temp << 1) & 0xffffffff

            temp = ((left << 8) | ((right >> 20) & 0x000000f0)) & 0xffffffff
            left = ((right << 24) | ((right << 8) & 0xff0000) | ((right >> 8) & 0xff00) | ((right >> 24) & 0xf0)) & 0xffffffff
            right = temp

            for i in range(0, len(shifts)):
                if shifts[i]:
                    left = ((left << 2) | (left >> 26)) & 0xffffffff
                    right = ((right << 2) | (right >> 26)) & 0xffffffff
                else:
                    left = ((left << 1) | (left >> 27)) & 0xffffffff
                    right = ((right << 1) | (right >> 27)) & 0xffffffff

                left &= 0xfffffff0
                right &= 0xfffffff0

                lefttemp = (
                    pc2bytes0[left >> 28] |
                    pc2bytes1[(left >> 24) & 0xf] |
                    pc2bytes2[(left >> 20) & 0xf] |
                    pc2bytes3[(left >> 16) & 0xf] |
                    pc2bytes4[(left >> 12) & 0xf] |
                    pc2bytes5[(left >> 8) & 0xf] |
                    pc2bytes6[(left >> 4) & 0xf])

                righttemp = (
                    pc2bytes7[right >> 28] |
                    pc2bytes8[(right >> 24) & 0xf] |
                    pc2bytes9[(right >> 20) & 0xf] |
                    pc2bytes10[(right >> 16) & 0xf] |
                    pc2bytes11[(right >> 12) & 0xf] |
                    pc2bytes12[(right >> 8) & 0xf] |
                    pc2bytes13[(right >> 4) & 0xf])

                temp = ((righttemp >> 16) ^ lefttemp) & 0x0000ffff
                keys[n] = (lefttemp ^ temp) & 0xffffffff
                keys[n + 1] = (righttemp ^ (temp << 16)) & 0xffffffff
                n += 2
        return keys


if __name__ == "__main__":
    des = DES(b"testtest")
    res = des.encrypt(b"HELLO,WORLD!")
    text = des.decrypt(res)
    print("DES ECB: encrypt:%s, decrypt:%s" % (res.hex(), text))

    res = des.encrypt(b"HELLO,WORLD!", mode="CBC", iv=b"12345678")
    text = des.decrypt(res, mode="CBC", iv=b"12345678")
    print("DES CBC: encrypt:%s, decrypt:%s" % (res.hex(), text))

你可能感兴趣的:(python,算法,安全)