首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >加解密算法

加解密算法
EN

Code Review用户
提问于 2021-04-21 17:10:53
回答 2查看 214关注 0票数 6

我已经做了很长一段时间了,现在我已经有了一个工作计划,我想我会看到其他人对它的看法。

基本上,如果你认为有什么东西能使它更快、更简单,或者让它变得更好,请分享你的想法。至于实际力量,我不知道如何测试。是的,我知道我应该使用AES,但这只是为了练习和娱乐。

总之,这是密码。(255行,对不起)

代码语言:javascript
复制
import base64
import os
import random
# from datetime import datetime


def add_padding(s, i=128):
    padding = len(s) % i

    for j in range(i - padding):
        s += '='
    
    s = ascii_to_bin(s)
    
    # make last byte equal to number of padding bytes
    s = s[:len(s) - 8] + decimal_to_binary([i - padding])
    
    return s 


def xor_string(k, s):
    xored_secret = ''
    
    for i in range(len(s) // len(k)):
        if i > 0:
            k = round_key(k)
        
        xored_secret += decimal_to_binary([bin_to_decimal(k, len(k))[0] ^ bin_to_decimal(s[i * len(k):len(k) + (i * len(k))], len(k))[0]], len(k))
    
    return xored_secret


def generate_key(k):
    if len(k) == 128:
        k = ascii_to_bin(k)
        return k
    elif len(k) < 128:
        
        k = ascii_to_decimal(k)
        
        for i in range(128 - len(k)):
            b = decimal_to_binary([k[i]])
            b = xor_string(decimal_to_binary([int(sum(k) / len(k))]), b[::-1])
            
            k.append(int(b, 2))
        
        s = ''
        for i in k:
            s += str(i)
        
        j = str(s[:len(s) // 2])
        y = str(s[len(s) // 2:])
        s = decimal_to_binary([int(y + j)])
        s = s[:1024]
        return s


def bin_to_base64(binary):
    return base64.b64encode(bytes([int(binary[i * 8:8 + i * 8], 2) for i in range(len(binary) // 8)])).decode()


def ascii_to_bin(string):
    return decimal_to_binary(ascii_to_decimal(string))


def bin_to_decimal(binary, length=8):
    b = [binary[i * length:length + (i * length)] for i in range(len(binary) // length)]

    decimal = [int(i, 2) for i in b]

    # returns an list of ints
    return decimal


def decimal_to_binary(decimal, length=8):
    output = ''
    for i in range(len(decimal)):
        output += str(bin(decimal[i])[2:].zfill(length))
        
    # returns a string
    return output


def ascii_to_decimal(string):
    # returns a list of ints
    return [ord(i) for i in string]


def bin_to_ascii(binary):
    x = bin_to_decimal(binary)
    s = ''
    for i in x:
        s += chr(i)
    
    # returns a string
    return s


def base64_to_bin(base):
    decoded = ''
    for letter in base64.b64decode(base):
        # print(letter)
        decoded += bin(letter)[2:].zfill(8)

    return decoded

def matrix_to_str(m):
    s = ''
    for i in range(32):
        for j in range(32):
            s += str(m[i][j])
    
    return s


def obfuscate(binary, k, x, xd):
    b = ''
    d = k  # donkey kong

    for i in range(len(binary) // 1024):
        if i > 0:
            d = round_key(d)
        
        # m = [list(binary[j * 32 + i * 1024:j * 32 + i * 1024 + 32]) for j in range(32)]
        
        if x:
            m = [list(binary[j * 32 + i * 1024:j * 32 + i * 1024 + 32]) for j in range(32)]
            m = shuffle(m, bin_to_decimal(d, 1024)[0], xd)
            b += xor_string(d, matrix_to_str(m))
        elif not x:
            xor = xor_string(d, binary[i * 1024:i * 1024 + 1024])
            m = [list(xor[j * 32:j * 32 + 32]) for j in range(32)]
            m = reverse_shuffle(m, bin_to_decimal(d, 1024)[0], xd)
            b += matrix_to_str(m)
        
    return xor_string(k, b)


def shuffle(m, d, xd):
    for j in range(xd):
        # move columns to the right
        m = [row[-1:] + row[:-1] for row in m]
    
        # move rows down
        m = m[-1:] + m[:-1]
        
        shuffled_m = [[0] * 32 for _ in range(32)]

        for idx, sidx in enumerate(test(d)):
            shuffled_m[idx // 32][idx % 32] = m[sidx // 32][sidx % 32]

        m = shuffled_m

        # cut in half and flip halves
        m = m[len(m) // 2:] + m[:len(m) // 2]

        # test
        m = list(map(list, zip(*m)))
    
    return m


def reverse_shuffle(m, d, xd):
    for j in range(xd):
        # test
        m = list(map(list, zip(*m)))
        
        # cut in half and flip halves
        m = m[len(m) // 2:] + m[:len(m) // 2]
        
        shuffled_m = [[0] * 32 for _ in range(32)]
        
        for idx, sidx in enumerate(test(d)):
            shuffled_m[sidx // 32][sidx % 32] = m[idx // 32][idx % 32]
        
        m = shuffled_m
        
        # move rows up
        m = m[1:] + m[:1]
        
        # move columns to the left
        m = [row[1:] + row[:1] for row in m]
    
    return m


def test(d):
    random.seed(d)
    lst = list(range(1024))
    random.shuffle(lst)
    
    return lst


def round_key(k):
    k = [[k[(j * 32 + n)] for n in range(32)] for j in range(32)]
    # get the last column
    col = [i[-1] for i in k]
    # interweave
    col = [x for i in range(len(col) // 2) for x in (col[-i - 1], col[i])]
    new_key = ''
    for i in range(32):
        cols = ''
        for row in k:
            cols += row[i]
        
        cols = cols[16:] + cols[:16]
        new_key += xor_string(''.join(str(ele) for ele in col), cols)
    
    return new_key


def encrypt(p, s, xd):
    k = generate_key(p)
    s = add_padding(s)
    s = xor_string(k, s)
    s = obfuscate(s, k, True, xd)
    s = bin_to_base64(s)
    return s


def decrypt(p, b, xd):
    k = generate_key(p)
    b = base64_to_bin(b)
    b = xor_string(k, b)
    b = obfuscate(b, k, False, xd)
    pad = b[len(b) - 8:]
    b = bin_to_ascii(b)
    b = b[:len(b) - bin_to_decimal(pad)[0]]
    return b


if __name__ == '__main__':
    while True:
        os.system('cls')
        com = input('1)Encrypt Text \n2)Decrypt Text\n3)Exit\n')

        if com == '1':
            os.system('cls')
            secret = input('Enter the text you wish to encrypt: ')
            os.system('cls')
            key = input('Enter your key: ')
            os.system('cls')
            print(f'Encrypted text: {encrypt(key, secret, 1)}') # the 1 is the number of loops, I'm not sure how many I should do :/
            input()
        elif com == '2':
            os.system('cls')
            b64 = input('Enter the text you wish to decrypt: ')
            os.system('cls')
            key = input('Enter your key: ')
            os.system('cls')
            print(f'Decrypted text: {decrypt(key, b64, 1)}')
            input()
        elif com == '3':
            break

如果你需要澄清什么,就问吧。谢谢!

EN

回答 2

Code Review用户

回答已采纳

发布于 2021-04-22 05:39:16

添加填充

代码语言:javascript
复制
def add_padding(s, i=128):
    padding = len(s) % i

    for j in range(i - padding):
        s += '='

    ...

如果s是127个字符,则padding变为127个,但只添加1个=字符。

如果s为128个字符,则padding变为零,这是合理的。但是,128个=字符被添加到字符串中,这确实是出乎意料的。我知道这是必要的,因为你用填充的量代替了最后一个,但它违反了最不惊讶的原则。

用..。

代码语言:javascript
复制
s += '=' * (i - padding)

比循环更有效率。

在添加填充并将其转换为位后,可以删除填充的最后8位,用填充的长度替换它。如果一开始不添加额外的填充字符,就可以节省一些工作。

下面是一些重新加工的代码:

代码语言:javascript
复制
def add_padding(message, frame_size=128):
    payload_len = len(message) + 1        # Extra character encodes padding length
    padding = -payload_len % frame_size   # Amount of padding needed to fill frame

    frames = message + '=' * padding + chr(padding + 1)
    return ascii_to_bin(frames)

ASCII到十进制

代码语言:javascript
复制
def ascii_to_decimal(string):
    # returns a list of ints
    return [ord(i) for i in string]

虽然这看起来很简单,但是大部分代码都需要8位字节,而不是整数。字符串中的第一个ā将被转换为257个,随后的bin(letter)[2:].zfill(length)将扩展为'100000001',尽管它的长度超过8个字符。

Python有一个内置函数,它将字符串转换为字节数组。str.encode()。默认情况下,它将使用UTF-8编码,并根据需要将非ASCII字符编码为多个字节:

代码语言:javascript
复制
>>> msg = 'cbā'
>>> msg_bytes = msg.encode()
>>> print(len(msg), len(msg_bytes), type(msg_bytes))
3 4 <class 'bytes'>

但是请注意,字节数组的长度(在本例中)大于字符串的长度,这会使填充混乱。最简单的解决方法是将字符串转换为字节数组,然后确定需要填充多少空间,并将其添加到字节数组中。

代码语言:javascript
复制
>>> msg_bytes = msg.encode()
>>> payload_len = len(msg_bytes) + 1
>>> padding = -payload_len % frame_size
>>> frames = msg_bytes + b'=' * padding + bytes([padding + 1])

另外,bytes (只读)和bytearray (可变)对象比使用整数列表的效率要高得多,因此通过切换到它们可以获得一定的速度和/或内存效率。

要在解码步骤中逆转这一点,请执行以下步骤:

代码语言:javascript
复制
>>> padding = frames[-1]            # amount of padding added
>>> msg_bytes = frames[:-padding]   # unpadded message bytes
>>> msg = msg_bytes.decode()        # decode bytes back to a string
>>> msg
'cbā'
票数 5
EN

Code Review用户

发布于 2021-04-21 23:22:07

欢迎来到代码评审。

good things

  • 合理函数名
  • 通过将CLI放入if __name__ == '__main__':块使其变得重要
  • 良好的缩进和使用空白

建议

  • 将整个函数填充到return行在ascii_to_bin上比在bin_to_base64上工作得更好。
  • 单字变量名是不允许的,因为它们很容易让人们感到困惑。使用key而不是k之类的方法可以帮助代码更加可读性
  • 在出现一个严重的蟒蛇之前,你应该先读一读PEP8。在这方面有帮助的指针。
  • 这仅限于在DOS派生的系统上运行。cls并不存在于Mac或Linux上。这里是一个可移植的解决方案。
  • 包括一个sh-bang行(#!),以澄清应该在哪个python下运行。
票数 5
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/259814

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档