Python等同于PHP的MCRYPT_RIJNDAEL_256 CBC

发布于 2021-01-29 16:21:16

我需要此功能的Python实现-我想在appengine上使用它。

我的Python不太好,请帮忙。

function encrypt($data) {
  return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256 ,'oqufXQ(?bc=6_hR2I3sMZChDpb6dDlw4', $data , MCRYPT_MODE_CBC, utf8_encode('fOaiIOkD8*9Xeu_s4_bb87Ox_UG+D9GA')));
}
关注者
0
被浏览
169
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    您是否尝试过这个(也包括在下面)?它实现了16、24或32字节的Rijndael分组密码。您正在使用256位(32字节)版本的分组密码。

    """
    A pure python (slow) implementation of rijndael with a decent interface
    
    To include -
    
    from rijndael import rijndael
    
    To do a key setup -
    
    r = rijndael(key, block_size = 16)
    
    key must be a string of length 16, 24, or 32
    blocksize must be 16, 24, or 32. Default is 16
    
    To use -
    
    ciphertext = r.encrypt(plaintext)
    plaintext = r.decrypt(ciphertext)
    
    If any strings are of the wrong length a ValueError is thrown
    """
    
    # ported from the Java reference code by Bram Cohen, April 2001
    # this code is public domain, unless someone makes 
    # an intellectual property claim against the reference 
    # code, in which case it can be made public domain by 
    # deleting all the comments and renaming all the variables
    
    import copy
    import string
    
    shifts = [[[0, 0], [1, 3], [2, 2], [3, 1]],
              [[0, 0], [1, 5], [2, 4], [3, 3]],
              [[0, 0], [1, 7], [3, 5], [4, 4]]]
    
    # [keysize][block_size]
    num_rounds = {16: {16: 10, 24: 12, 32: 14}, 24: {16: 12, 24: 12, 32: 14}, 32: {16: 14, 24: 14, 32: 14}}
    
    A = [[1, 1, 1, 1, 1, 0, 0, 0],
         [0, 1, 1, 1, 1, 1, 0, 0],
         [0, 0, 1, 1, 1, 1, 1, 0],
         [0, 0, 0, 1, 1, 1, 1, 1],
         [1, 0, 0, 0, 1, 1, 1, 1],
         [1, 1, 0, 0, 0, 1, 1, 1],
         [1, 1, 1, 0, 0, 0, 1, 1],
         [1, 1, 1, 1, 0, 0, 0, 1]]
    
    # produce log and alog tables, needed for multiplying in the
    # field GF(2^m) (generator = 3)
    alog = [1]
    for i in range(255):
        j = (alog[-1] << 1) ^ alog[-1]
        if j & 0x100 != 0:
            j ^= 0x11B
        alog.append(j)
    
    log = [0] * 256
    for i in range(1, 255):
        log[alog[i]] = i
    
    # multiply two elements of GF(2^m)
    def mul(a, b):
        if a == 0 or b == 0:
            return 0
        return alog[(log[a & 0xFF] + log[b & 0xFF]) % 255]
    
    # substitution box based on F^{-1}(x)
    box = [[0] * 8 for i in range(256)]
    box[1][7] = 1
    for i in range(2, 256):
        j = alog[255 - log[i]]
        for t in range(8):
            box[i][t] = (j >> (7 - t)) & 0x01
    
    B = [0, 1, 1, 0, 0, 0, 1, 1]
    
    # affine transform:  box[i] <- B + A*box[i]
    cox = [[0] * 8 for i in range(256)]
    for i in range(256):
        for t in range(8):
            cox[i][t] = B[t]
            for j in range(8):
                cox[i][t] ^= A[t][j] * box[i][j]
    
    # S-boxes and inverse S-boxes
    S =  [0] * 256
    Si = [0] * 256
    for i in range(256):
        S[i] = cox[i][0] << 7
        for t in range(1, 8):
            S[i] ^= cox[i][t] << (7-t)
        Si[S[i] & 0xFF] = i
    
    # T-boxes
    G = [[2, 1, 1, 3],
        [3, 2, 1, 1],
        [1, 3, 2, 1],
        [1, 1, 3, 2]]
    
    AA = [[0] * 8 for i in range(4)]
    
    for i in range(4):
        for j in range(4):
            AA[i][j] = G[i][j]
            AA[i][i+4] = 1
    
    for i in range(4):
        pivot = AA[i][i]
        if pivot == 0:
            t = i + 1
            while AA[t][i] == 0 and t < 4:
                t += 1
                assert t != 4, 'G matrix must be invertible'
                for j in range(8):
                    AA[i][j], AA[t][j] = AA[t][j], AA[i][j]
                pivot = AA[i][i]
        for j in range(8):
            if AA[i][j] != 0:
                AA[i][j] = alog[(255 + log[AA[i][j] & 0xFF] - log[pivot & 0xFF]) % 255]
        for t in range(4):
            if i != t:
                for j in range(i+1, 8):
                    AA[t][j] ^= mul(AA[i][j], AA[t][i])
                AA[t][i] = 0
    
    iG = [[0] * 4 for i in range(4)]
    
    for i in range(4):
        for j in range(4):
            iG[i][j] = AA[i][j + 4]
    
    def mul4(a, bs):
        if a == 0:
            return 0
        r = 0
        for b in bs:
            r <<= 8
            if b != 0:
                r = r | mul(a, b)
        return r
    
    T1 = []
    T2 = []
    T3 = []
    T4 = []
    T5 = []
    T6 = []
    T7 = []
    T8 = []
    U1 = []
    U2 = []
    U3 = []
    U4 = []
    
    for t in range(256):
        s = S[t]
        T1.append(mul4(s, G[0]))
        T2.append(mul4(s, G[1]))
        T3.append(mul4(s, G[2]))
        T4.append(mul4(s, G[3]))
    
        s = Si[t]
        T5.append(mul4(s, iG[0]))
        T6.append(mul4(s, iG[1]))
        T7.append(mul4(s, iG[2]))
        T8.append(mul4(s, iG[3]))
    
        U1.append(mul4(t, iG[0]))
        U2.append(mul4(t, iG[1]))
        U3.append(mul4(t, iG[2]))
        U4.append(mul4(t, iG[3]))
    
    # round constants
    rcon = [1]
    r = 1
    for t in range(1, 30):
        r = mul(2, r)
        rcon.append(r)
    
    del A
    del AA
    del pivot
    del B
    del G
    del box
    del log
    del alog
    del i
    del j
    del r
    del s
    del t
    del mul
    del mul4
    del cox
    del iG
    
    class rijndael:
        def __init__(self, key, block_size = 16):
            if block_size != 16 and block_size != 24 and block_size != 32:
                raise ValueError('Invalid block size: ' + str(block_size))
            if len(key) != 16 and len(key) != 24 and len(key) != 32:
                raise ValueError('Invalid key size: ' + str(len(key)))
            self.block_size = block_size
    
            ROUNDS = num_rounds[len(key)][block_size]
            BC = block_size // 4
            # encryption round keys
            Ke = [[0] * BC for i in range(ROUNDS + 1)]
            # decryption round keys
            Kd = [[0] * BC for i in range(ROUNDS + 1)]
            ROUND_KEY_COUNT = (ROUNDS + 1) * BC
            KC = len(key) // 4
    
            # copy user material bytes into temporary ints
            tk = []
            for i in range(0, KC):
                tk.append((ord(key[i * 4]) << 24) | (ord(key[i * 4 + 1]) << 16) |
                    (ord(key[i * 4 + 2]) << 8) | ord(key[i * 4 + 3]))
    
            # copy values into round key arrays
            t = 0
            j = 0
            while j < KC and t < ROUND_KEY_COUNT:
                Ke[t // BC][t % BC] = tk[j]
                Kd[ROUNDS - (t // BC)][t % BC] = tk[j]
                j += 1
                t += 1
            tt = 0
            rconpointer = 0
            while t < ROUND_KEY_COUNT:
                # extrapolate using phi (the round key evolution function)
                tt = tk[KC - 1]
                tk[0] ^= (S[(tt >> 16) & 0xFF] & 0xFF) << 24 ^  \
                         (S[(tt >>  8) & 0xFF] & 0xFF) << 16 ^  \
                         (S[ tt        & 0xFF] & 0xFF) <<  8 ^  \
                         (S[(tt >> 24) & 0xFF] & 0xFF)       ^  \
                         (rcon[rconpointer]    & 0xFF) << 24
                rconpointer += 1
                if KC != 8:
                    for i in range(1, KC):
                        tk[i] ^= tk[i-1]
                else:
                    for i in range(1, KC // 2):
                        tk[i] ^= tk[i-1]
                    tt = tk[KC // 2 - 1]
                    tk[KC // 2] ^= (S[ tt        & 0xFF] & 0xFF)       ^ \
                                   (S[(tt >>  8) & 0xFF] & 0xFF) <<  8 ^ \
                                   (S[(tt >> 16) & 0xFF] & 0xFF) << 16 ^ \
                                   (S[(tt >> 24) & 0xFF] & 0xFF) << 24
                    for i in range(KC // 2 + 1, KC):
                        tk[i] ^= tk[i-1]
                # copy values into round key arrays
                j = 0
                while j < KC and t < ROUND_KEY_COUNT:
                    Ke[t // BC][t % BC] = tk[j]
                    Kd[ROUNDS - (t // BC)][t % BC] = tk[j]
                    j += 1
                    t += 1
            # inverse MixColumn where needed
            for r in range(1, ROUNDS):
                for j in range(BC):
                    tt = Kd[r][j]
                    Kd[r][j] = U1[(tt >> 24) & 0xFF] ^ \
                               U2[(tt >> 16) & 0xFF] ^ \
                               U3[(tt >>  8) & 0xFF] ^ \
                               U4[ tt        & 0xFF]
            self.Ke = Ke
            self.Kd = Kd
    
        def encrypt(self, plaintext):
            if len(plaintext) != self.block_size:
                raise ValueError('wrong block length, expected ' + str(self.block_size) + ' got ' + str(len(plaintext)))
            Ke = self.Ke
    
            BC = self.block_size // 4
            ROUNDS = len(Ke) - 1
            if BC == 4:
                SC = 0
            elif BC == 6:
                SC = 1
            else:
                SC = 2
            s1 = shifts[SC][1][0]
            s2 = shifts[SC][2][0]
            s3 = shifts[SC][3][0]
            a = [0] * BC
            # temporary work array
            t = []
            # plaintext to ints + key
            for i in range(BC):
                t.append((ord(plaintext[i * 4    ]) << 24 |
                          ord(plaintext[i * 4 + 1]) << 16 |
                          ord(plaintext[i * 4 + 2]) <<  8 |
                          ord(plaintext[i * 4 + 3])        ) ^ Ke[0][i])
            # apply round transforms
            for r in range(1, ROUNDS):
                for i in range(BC):
                    a[i] = (T1[(t[ i           ] >> 24) & 0xFF] ^
                            T2[(t[(i + s1) % BC] >> 16) & 0xFF] ^
                            T3[(t[(i + s2) % BC] >>  8) & 0xFF] ^
                            T4[ t[(i + s3) % BC]        & 0xFF]  ) ^ Ke[r][i]
                t = copy.copy(a)
            # last round is special
            result = []
            for i in range(BC):
                tt = Ke[ROUNDS][i]
                result.append((S[(t[ i           ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF)
                result.append((S[(t[(i + s1) % BC] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF)
                result.append((S[(t[(i + s2) % BC] >>  8) & 0xFF] ^ (tt >>  8)) & 0xFF)
                result.append((S[ t[(i + s3) % BC]        & 0xFF] ^  tt       ) & 0xFF)
            return ''.join(map(chr, result))
    
        def decrypt(self, ciphertext):
            if len(ciphertext) != self.block_size:
                raise ValueError('wrong block length, expected ' + str(self.block_size) + ' got ' + str(len(ciphertext)))
            Kd = self.Kd
    
            BC = self.block_size // 4
            ROUNDS = len(Kd) - 1
            if BC == 4:
                SC = 0
            elif BC == 6:
                SC = 1
            else:
                SC = 2
            s1 = shifts[SC][1][1]
            s2 = shifts[SC][2][1]
            s3 = shifts[SC][3][1]
            a = [0] * BC
            # temporary work array
            t = [0] * BC
            # ciphertext to ints + key
            for i in range(BC):
                t[i] = (ord(ciphertext[i * 4    ]) << 24 |
                        ord(ciphertext[i * 4 + 1]) << 16 |
                        ord(ciphertext[i * 4 + 2]) <<  8 |
                        ord(ciphertext[i * 4 + 3])        ) ^ Kd[0][i]
            # apply round transforms
            for r in range(1, ROUNDS):
                for i in range(BC):
                    a[i] = (T5[(t[ i           ] >> 24) & 0xFF] ^
                            T6[(t[(i + s1) % BC] >> 16) & 0xFF] ^
                            T7[(t[(i + s2) % BC] >>  8) & 0xFF] ^
                            T8[ t[(i + s3) % BC]        & 0xFF]  ) ^ Kd[r][i]
                t = copy.copy(a)
            # last round is special
            result = []
            for i in range(BC):
                tt = Kd[ROUNDS][i]
                result.append((Si[(t[ i           ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF)
                result.append((Si[(t[(i + s1) % BC] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF)
                result.append((Si[(t[(i + s2) % BC] >>  8) & 0xFF] ^ (tt >>  8)) & 0xFF)
                result.append((Si[ t[(i + s3) % BC]        & 0xFF] ^  tt       ) & 0xFF)
            return ''.join(map(chr, result))
    
    def encrypt(key, block):
        return rijndael(key, len(block)).encrypt(block)
    
    def decrypt(key, block):
        return rijndael(key, len(block)).decrypt(block)
    

    请注意,该rijndael.py文件仅实现分组密码。该encrypt/decrypt功能只会处理恰恰是块大小明文。这意味着这些函数的调用者将必须提供操作的分组密码模式以及他自己的零填充。

    示例python代码(请注意,来自Java程序员):

    class zeropad:
    
        def __init__(self, block_size):
            assert block_size > 0 and block_size < 256
            self.block_size = block_size
    
        def pad(self, pt):
            ptlen = len(pt)
            padsize = self.block_size - ((ptlen + self.block_size - 1) % self.block_size + 1)
            return pt + "\0" * padsize
    
        def unpad(self, ppt):
            assert len(ppt) % self.block_size == 0
            offset = len(ppt)
            if (offset == 0):
                return ''
            end = offset - self.block_size + 1
            while (offset > end):
                offset -= 1;
                if (ppt[offset] != "\0"):
                    return ppt[:offset + 1]
            assert false
    
    class cbc:
    
        def __init__(self, padding, cipher, iv):
            assert padding.block_size == cipher.block_size;
            assert len(iv) == cipher.block_size;
            self.padding = padding
            self.cipher = cipher
            self.iv = iv
    
        def encrypt(self, pt):
            ppt = self.padding.pad(pt)
            offset = 0
            ct = ''
            v = self.iv
            while (offset < len(ppt)):
                block = ppt[offset:offset + self.cipher.block_size]
                block = self.xorblock(block, v)
                block = self.cipher.encrypt(block)
                ct += block
                offset += self.cipher.block_size
                v = block
            return ct;
    
        def decrypt(self, ct):
            assert len(ct) % self.cipher.block_size == 0
            ppt = ''
            offset = 0
            v = self.iv
            while (offset < len(ct)):
                block = ct[offset:offset + self.cipher.block_size]
                decrypted = self.cipher.decrypt(block)
                ppt += self.xorblock(decrypted, v)
                offset += self.cipher.block_size
                v = block
            pt = self.padding.unpad(ppt)
            return pt;
    
        def xorblock(self, b1, b2):
            # sorry, not very Pythonesk
            i = 0
            r = '';
            while (i < self.cipher.block_size):
                 r += chr(ord(b1[i]) ^ ord(b2[i]))
                 i += 1
            return r
    


知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看